vue3 局部状态管理
vue3 父子组件通信能满足大部分的需求,无需应用状态管理。但某功能模块内组件多、层级深时,就可能有状态管理的需求。
Provide / Inject
若仅需要在某个模块内管理状态,完全可以使用 vue3 的 provide
/ inject
api,在模块的根组件上定义数据,后代组件中注入依赖
在线查看示例
模块根组件中定义数据及管理方法
js
const data = reactive({
name: 'Zzz',
info: { age: null, gender: null },
})
provide('data', readonly(data))
provide('setName', val => (data.name = val))
provide('setInfo', info => {
Object.assign(data.info, info)
})
后代组件中注入使用
js
const data = inject('data')
const setName = inject('setName')
const setInfo = inject('setInfo')
注意,注入后,直接更改引用类型内部数据会增加管理上的混乱,是需要避免的。因为多个组件可能会同时修改和访问同一个状态,导致难以追踪和理解状态的变化。
为了避免管理上的混乱,在设计状态管理时:
- 明确定义状态的作用域和职责,确保每个状态只被相关的组件使用和修改。
- 使用明确的操作来更新状态。建议使用具有明确目的的方法来更新状态,而不是直接修改引用类型状态的内部值。这样可以更容易地跟踪和理解状态的变化。
vuex / pinia
参照官方文档
pinia
示例:
store.js
:
选项式风格
js
import { defineStore } from 'pinia'
export const usePatientStore = defineStore('patient', {
state: () => ({
name: 'Zzz',
info: { age: null, gender: null },
}),
actions: {
setName(val) {
this.name = val
},
setInfo(data) {
if (typeof data === 'object') {
Object.assign(this.info, data)
}
},
},
})
组合式风格
js
import { ref, reactive } from 'vue'
import { defineStore } from 'pinia'
export const usePatientStore = defineStore('patient', () => {
const name = ref('Zzz')
const info = reactive({ age: null, gender: null })
const setName = (val) => {
name.value = val
}
const setInfo = (data) => {
if (typeof data === 'object') {
Object.assign(info, data)
}
}
return { name, info, setName, setInfo }
})
使用:
js
import { usePatientStore } from './store.js'
const patientStore = usePatientStore()
// 读取
console.log(patientStore.name)
// actions
function handleSetInfo() {
patientStore.setInfo({ age: 18, gender: 'male' })
}
store 模式
对于简单的需求,完全可以使用 store 模式实现局部状态管理
在线查看示例
store.js
:
js
import { reactive } from 'vue'
export default {
state: reactive({
name: 'Zzz',
info: { age: null, gender: null },
}),
setInfo(data) {
if (typeof data === 'object') Object.assign(this.state.info, data)
},
}
使用:
js
import store from './store.js'
function handleSetInfo() {
store.setInfo({ age: 18, gender: 'male' })
}
EventBus
组件间通信利器
mitt:
mitt
是一个轻量级的JavaScript事件总线库,拥有简单而强大的API,总体大小仅为200字节。它具有与Node.js的EventEmitter类似的API和命名约定,并且没有依赖项。它支持IE9+以及任何JavaScript运行时环境。
使用示例
js
import mitt from 'mitt'
const emitter = mitt()
// listen to an event
emitter.on('foo', e => console.log('foo', e) )
// listen to all events
emitter.on('*', (type, e) => console.log(type, e) )
// fire an event
emitter.emit('foo', { a: 'b' })
// clearing all events
emitter.all.clear()
// working with handler references:
function onFoo() {}
emitter.on('foo', onFoo) // listen
emitter.off('foo', onFoo) // unlisten
有时间可以看看它的源码,非常精简,几分钟就能看完
或者查看另一篇文章Mitt源码学习
Last updated: