1、用过module,项目规模变大之后,单独一个store对象会过于庞大臃肿,通过模块方式可以拆分开来便于维护
2、可以按之前规则单独编写子模块代码,然后在主文件中通过modules
选项组织起来:createStore({modules:{...}})
3、不过使用时要注意访问子模块状态时需要加上注册时模块名:store.state.a.xxx
,但同时getters
、mutations
和actions
又在全局空间中,使用方式和之前一样。如果要做到完全拆分,需要在子模块加上namespace
选项,此时再访问它们就要加上命名空间前缀。
很显然,模块的方式可以拆分代码,但是缺点也很明显,就是使用起来比较繁琐复杂,容易出错。而且类型系统支持很差,不能给我们带来帮助。pinia显然在这方面有了很大改进,是时候切换过去了。
修改状态只能是mutations
,actions
只能通过提交mutation
修改状态即可
官方文档说:更改 Vuex 的 store 中的状态的唯一方法是提交 mutation
,mutation
非常类似于事件:每个 mutation
都有一个字符串的类型 (type)*和一个* 回调函数 (handler) 。Action
类似于 mutation
,不同在于:Action
可以包含任意异步操作,但它不能修改状态, 需要提交mutation
才能变更状态。
因此,开发时,包含异步操作或者复杂业务组合时使用action;需要直接修改状态则提交mutation。但由于dispatch和commit是两个API,容易引起混淆,实践中也会采用统一使用dispatch action的方式。
调用dispatch和commit两个API时几乎完全一样,但是定义两者时却不甚相同,mutation的回调函数接收参数是state对象。action则是与Store实例具有相同方法和属性的上下文context对象,因此一般会解构它为{commit, dispatch, state}
,从而方便编码。另外dispatch会返回Promise实例便于处理内部异步结果。
实现上commit(type)方法相当于调用options.mutations[type](state)
;dispatch(type)
方法相当于调用options.actions[type](store)
,这样就很容易理解两者使用上的不同了。
如何从零写一个vuex?思路是什么?
- 官方说
vuex
是一个状态管理模式和库,并确保这些状态以可预期的方式变更。可见要实现一个vuex
:- 要实现一个
Store
存储全局状态 - 要提供修改状态所需API:
commit(type, payload)
,dispatch(type, payload)
- 要实现一个
- 实现
Store
时,可以定义Store类,构造函数接收选项options,设置属性state对外暴露状态,提供commit和dispatch修改属性state。这里需要设置state为响应式对象,同时将Store定义为一个Vue插件。 commit(type, payload)
方法中可以获取用户传入mutations
并执行它,这样可以按用户提供的方法修改状态。dispatch(type, payload)
类似,但需要注意它可能是异步的,需要返回一个Promise给用户以处理异步结果。
class Store {
constructor(options) {
this.state = reactive(options.state)
this.options = options
}
commit(type, payload) {
this.options.mutations[type].call(this, this.state, payload)
}
}
vuex如何监听数据的变化?
可以通过watch选项或者watch方法监听状态
可以使用vuex提供的API:store.subscribe()
watch选项方式,可以以字符串形式监听$store.state.xx
;subscribe方式,可以调用store.subscribe(cb),回调函数接收mutation对象和state对象,这样可以进一步判断mutation.type是否是期待的那个,从而进一步做后续处理。
watch方式简单好用,且能获取变化前后值,首选;subscribe方法会被所有commit行为触发,因此还需要判断mutation.type,用起来略繁琐,一般用于vuex插件中。
// watch
const app = createApp({
watch: {
'$store.state.counter'() {
console.log('counter change!');
}
}
})
// subscrible
store.subscribe((mutation, state) => {
if (mutation.type === 'add') {
console.log('counter change in subscribe()!');
}
})