vuex中更新state的方法
首页,在 vuex 中只有 mutations 可以更新state
- commit 一个 mutation,mutation 负责更改 state
- dispatch 一个 action,在 action 中 commit 一个 mutation
所以按照上述使用方法,我们在使用时,如果不涉及异步操作,可以直接 commit 一个 mutation 去更改 state,如果有异步就需要将异步方法写在 dispatch 中,然后在 dispatch 中commit mutation 去更改 state
我们从源码角度来回答这个问题,以下代码来自 vuex 源码,做了部分提示警告逻辑的删减,不影响整体逻辑,vue源码
// 这个就是 Store 类的 commit 方法
function commit (_type, _payload, _options) {
// check object-style commit
const {type, payload, options} = unifyObjectStyle(_type, _payload, _options)
// 定义mutation对象,type 其实就是我们要操作的 mutation 的方法名, payload 是参数(载荷)
const mutation = { type, payload }
// entry 就是要被执行的 mutation 方法
const entry = this._mutations[type]
// 省略了一些中间不影响逻辑的代码
// 注册一些回调函数,可以看到 mutation 方法(entry)最终是在这个回调函数中执行,直接就执行结束,没有任何的 return 以及 异步处理,这样也就是说在 commit 中不可以写异步逻辑
this._withCommit(() => {
entry.forEach(function commitIterator (handler) {
handler(payload)
})
})
this._subscribers
.slice() // shallow copy to prevent iterator invalidation if subscriber synchronously calls unsubscribe
.forEach(sub => sub(mutation, this.state))
}
function dispatch (_type, _payload) {
// check object-style dispatch
const {type,payload} = unifyObjectStyle(\type, _payload)
// 定义 action 对象,type 是 actions 对象中的一个属性,payload 是载荷
const action = { type, payload }
// 待执行的 action 方法
const entry = this._actions[type]
try {
this._actionSubscribers
.slice() // shallow copy to prevent iterator invalidation if subscriber synchronously calls unsubscribe
.filter(sub => sub.before)
.forEach(sub => sub.before(action, this.state))
} catch (e) {}
// 在这里执行了 action 方法,并将结果用 Promise.all 方法处理
const result = entry.length > 1
? Promise.all(entry.map(handler => handler(payload)))
: entry[0](payload)
// 这里的 result.then 执行完以后会 return 一个结果出去(其实就是我们自己调用的异步逻辑的结果)
return result.then(res => {
try {
this._actionSubscribers
.filter(sub => sub.after)
.forEach(sub => sub.after(action, this.state))
} catch (e) {}
return res
})
}
问题:
-
可以在mutations和actions里写异步请求,并被外部组件调用。但是在mutations里的异步请求成功后不能更新state,actions里的异步请求成功后可以commit调用mutations去更新state
-
如果我把异步函数写在外部组件里,请求成功后commit调用mutations更新state也是可以的
解答:
-
在组件中执行异步操作,在异步的回调中执行commit也可以,但是一般不这么做,理由是:state状态更新逻辑是可复用的,但是如果把这部分逻辑写在了组件内,比如写在了组件A中,这时候另外一个组件B也需要更新这个状态,你就需要把组件A中的那段异步代码复制到组件B中,这个不是一个合理的方式(代码冗余,应该将公共逻辑抽离出来),虽然可以这么做,但是不推荐。
-
从字面意思来看你是想在一个mutation写异步逻辑?然后在异步的回调中commit另外一个更新数据的mutation?说实话没有人这么做,也没必要这儿做,但是可以理解你的执着,这个是可以的,但是你需要在commit第一个mutation的时候在载荷(payload)中把commit对象传递进来,然后payload.commit(‘mutation2’, payload2)。