# 数据存储
# mutation
Vuex 对数据存储的存储本质上就是对 state 做修改,并且只允许我们通过提交 mutaion 的形式去修改 state,mutation 是一个函数,如下:
mutations: { increment (state) { state.count++ } }成功
2
3
4
5
mutations 的初始化也是在 installModule 的时候:
function installModule (store, rootState, path, module, hot) { // ... const namespace = store._modules.getNamespace(path) // ... const local = module.context = makeLocalContext(store, namespace, path) module.forEachMutation((mutation, key) => { const namespacedType = namespace + key registerMutation(store, namespacedType, mutation, local) }) // ... } function registerMutation (store, type, handler, local) { const entry = store._mutations[type] || (store._mutations[type] = []) entry.push(function wrappedMutationHandler (payload) { handler.call(store, local.state, payload) }) }成功
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
store 提供了commit 方法让我们提交一个 mutation:
commit (_type, _payload, _options) { // check object-style commit const { type, payload, options } = unifyObjectStyle(_type, _payload, _options) const mutation = { type, payload } const entry = this._mutations[type] if (!entry) { if (process.env.NODE_ENV !== 'production') { console.error(`[vuex] unknown mutation type: ${type}`) } return } this._withCommit(() => { entry.forEach(function commitIterator (handler) { handler(payload) }) }) this._subscribers.forEach(sub => sub(mutation, this.state)) if ( process.env.NODE_ENV !== 'production' && options && options.silent ) { console.warn( `[vuex] mutation type: ${type}. Silent option has been removed. ` + 'Use the filter functionality in the vue-devtools' ) } }成功
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
这里传入的 _type 就是 mutation 的 type,我们可以从 store._mutations 找到对应的函数数组,遍历它们执行获取到每个 handler 然后执行,实际上就是执行了 wrappedMutationHandler(playload),接着会执行我们定义的 mutation 函数,并传入当前模块的 state,所以我们的 mutation 函数也就是对当前模块的 state 做修改。
需要注意的是, mutation 必须是同步函数,但是我们在开发实际项目中,经常会遇到要先去发送一个请求,然后根据请求的结果去修改 state,那么单纯只通过 mutation 是无法完成需求,因此 Vuex 又给我们设计了一个 action 的概念。
# action
action 类似于 mutation,不同在于 action 提交的是 mutation,而不是直接操作 state,并且它可以包含任意异步操作。例如:
mutations: { increment (state) { state.count++ } }, actions: { increment (context) { setTimeout(() => { context.commit('increment') }, 0) } }成功
2
3
4
5
6
7
8
9
10
11
12
actions 的初始化也是在 installModule 的时候:
function installModule (store, rootState, path, module, hot) { // ... const namespace = store._modules.getNamespace(path) // ... const local = module.context = makeLocalContext(store, namespace, path) module.forEachAction((action, key) => { const type = action.root ? key : namespace + key const handler = action.handler || action registerAction(store, type, handler, local) } ) // ... } function registerAction (store, type, handler, local) { const entry = store._actions[type] || (store._actions[type] = []) entry.push(function wrappedActionHandler (payload, cb) { let res = handler.call(store, { dispatch: local.dispatch, commit: local.commit, getters: local.getters, state: local.state, rootGetters: store.getters, rootState: store.state }, payload, cb) if (!isPromise(res)) { res = Promise.resolve(res) } if (store._devtoolHook) { return res.catch(err => { store._devtoolHook.emit('vuex:error', err) throw err }) } else { return res } }) }成功
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
store 提供了dispatch 方法让我们提交一个 action:
dispatch (_type, _payload) { // check object-style dispatch const { type, payload } = unifyObjectStyle(_type, _payload) const action = { type, payload } const entry = this._actions[type] if (!entry) { if (process.env.NODE_ENV !== 'production') { console.error(`[vuex] unknown action type: ${type}`) } return } this._actionSubscribers.forEach(sub => sub(action, this.state)) return entry.length > 1 ? Promise.all(entry.map(handler => handler(payload))) : entry[0](payload) }成功
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
这里传入的 _type 就是 action 的 type,我们可以从 store._actions 找到对应的函数数组,遍历它们执行获取到每个 handler 然后执行,实际上就是执行了 wrappedActionHandler(payload),接着会执行我们定义的 action 函数,并传入一个对象,包含了当前模块下的 dispatch、commit、getters、state,以及全局的 rootState 和 rootGetters,所以我们定义的 action 函数能拿到当前模块下的 commit 方法。
因此 action 比我们自己写一个函数执行异步操作然后提交 muataion 的好处是在于它可以在参数中获取到当前模块的一些方法和状态,Vuex 帮我们做好了这些。