1、用过 module,项目规模变大之后,单独一个 store 对象会过于庞大臃肿,通过模块方式可以拆分开来便于维护

2、可以按之前规则单独编写子模块代码,然后在主文件中通过modules选项组织起来:createStore({modules:{...}})

3、不过使用时要注意访问子模块状态时需要加上注册时模块名:store.state.a.xxx,但同时gettersmutationsactions又在全局空间中,使用方式和之前一样。如果要做到完全拆分,需要在子模块加上namespace选项,此时再访问它们就要加上命名空间前缀。

很显然,模块的方式可以拆分代码,但是缺点也很明显,就是使用起来比较繁琐复杂,容易出错。而且类型系统支持很差,不能给我们带来帮助。pinia 显然在这方面有了很大改进,是时候切换过去了。

修改状态只能是mutationsactions只能通过提交mutation修改状态即可

官方文档说:更改 Vuex 的 store 中的状态的唯一方法是提交 mutationmutation 非常类似于事件:每个 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?思路是什么?

  1. 官方说vuex是一个状态管理模式和库,并确保这些状态以可预期的方式变更。可见要实现一个vuex
    • 要实现一个Store存储全局状态
    • 要提供修改状态所需 API:commit(type, payload), dispatch(type, payload)
  2. 实现Store时,可以定义 Store 类,构造函数接收选项 options,设置属性 state 对外暴露状态,提供 commit 和 dispatch 修改属性 state。这里需要设置 state 为响应式对象,同时将 Store 定义为一个 Vue 插件。
  3. commit(type, payload)方法中可以获取用户传入mutations并执行它,这样可以按用户提供的方法修改状态。 dispatch(type, payload)类似,但需要注意它可能是异步的,需要返回一个 Promise 给用户以处理异步结果。
1
2
3
4
5
6
7
8
9
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 插件中。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
// 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()!");
}
});