#基本概念
Vuex 和单纯的全局对象有以下两点不同:
单一状态树,用一个对象就包含了全部的应用层级状态。至此它便作为一个“唯一数据源 (SSOT)”而存在。
这也意味着,每个应用将仅仅包含一个 store 实例。单一状态树让我们能够直接地定位任一特定的状态片段,在调试的过程中也能轻易地取得整个当前应用状态的快照。
单状态树和模块化并不冲突,可以将状态和状态变更事件分布到各个子模块中。
mapState辅助函数,将多个状态传入。
组件仍然保有局部状态
有时候我们需要从 store 中的 state 中派生出一些状态。
getters接受state作为第一个参数。
const store = createStore({
state:{
todos:[
{id:1,text:'...',done:true},
{id:2,text:'...',done:false}
]
},
getters:{
doneTodos(state){
return state.todos.filter(to => todo.done);
}
}
})
getters会暴露store.getters对象,可以访问
注意,getter 在通过属性访问时是作为 Vue 的响应式系统的一部分缓存其中的。
也可以通过getter返回一个函数,来实现给getter传参,在对store里的数组进行查询
注意,getter 在通过方法访问时,每次都会去进行调用,而不会缓存结果。
更改 Vuex 的 store 中的状态的唯一方法是提交 mutation。
Vuex 中的 mutation 非常类似于事件:每个 mutation 都有一个字符串的事件类型 (type)和一个回调函数 (handler)。这个回调函数就是我们实际进行状态更改的地方,并且它会接受 state 作为第一个参数:
mutation 必须是同步函数
为了在调试时,知道状态是可追踪的。
//注册一个简单的action
const store = createStore({
state:{
count:0
},
mutations:{
increment(state) {
state.count++;
}
},
actions:{
increment(context){
context.commit('increment');
}
}
})
action接受一个与store实例具有相同方法和属性的context对象,因此可以调用context.commit提交一个mutation或者通过context.state和context.getters来获取state和getters。
这里为什么用的是context???? 而不是store实例本身呢?
action通常是异步的,那么如何知道action什么时候结束?如何组合多个action,来处理更加复杂的异步流程???
store.dispatch可以处理被触发的action的处理函数返回的Promise,并且store.dispatch仍旧返回promise
const store = createStore({
state:{},
mutations:{},
actions:{
actionA({commit}){
return new Promise((resolve,reject) => {
setTimeout(() => {
commit('someMutation')
resolve()
},1000)
})
}
}
})
store.dispatch('actionA').then(()=>{
}),
//在另一个action中也阔以
actions:{
actionB({dispatch,commi}){
return dispatch('actionA').then(()=>{
commit('someOtherMutation')
})
}
}
//最后利用async/await,进行如下组合action
actions:{
async actionA({commit}){
commit('gotData',await getData())
},
async actionB ({dispatch,commit}){
await dispatch('actionA')
commit('gotOtherData',await getOtherData())
}
}
一个store.dispatch 在不同模块中可以触发多个action函数,在这种情况下,只有当所有触发函数完成后,返回的promise才会执行。
由于使用单一状态树,应用的所有状态会集中到一个比较大的对象。应用十分复杂时,store对象就会变得臃肿。
解决上述问题,vuex允许我们将store分割成模块,每个模块拥有自己的state、mutation、action、getter甚至嵌套子模块,从上之下进行同样方式的分割
const moduleA = {
state: () => ({ ... }),
mutations: { ... },
actions: { ... },
getters: { ... }
}
const moduleB = {
state: () => ({ ... }),
mutations: { ... },
actions: { ... }
}
const store = createStore({
modules: {
a: moduleA,
b: moduleB
}
})
store.state.a // -> moduleA 的状态
store.state.b // -> moduleB 的状态
对于模块内部的mutation和getter,接收的第一个参数是模块的局部状态对象。
对于模块内部的action,局部状态通过context.state暴露出来,根节点状态则为contetx。rootState
vuex并不限制你的代码结构,但有一些需要遵守的规则:
1、应用层级的状态应该集中到单个store对象中
2、提交mutation是更改状态的唯一方法,并且这个过程是同步的
3、异步逻辑都应该封装到action里面
可以通过调用useStore函数,来在setup钩子函数中访问store,这与组件中使用选项式API访问this.$store是等效的
import {useStore} from 'vuex'
export default {
setup(){
const store = useStore()
return {
//在computed函数中访问state
count:computed(()=> store.state.count),
double:computed(() => store.getters.double),
increment:() => store.commit('increment');
asyncIncrement:() => store.dispatch('asyncIncrement')
}
}
}