寫在前面 通過上一講「Vuex 旗下的 Mutation」,我們知道瞭如何去修改 State 的數據,而且只能通過 Mutation 去提交修改,另外還瞭解到了 Mutation 必須是同步函數,那麼如果需求當中必須要用到非同步函數怎麼辦? 好辦,那就輪到 Action 上場了。 簡單介紹 Actio ...
寫在前面
通過上一講「Vuex 旗下的 Mutation」,我們知道瞭如何去修改 State 的數據,而且只能通過 Mutation 去提交修改,另外還瞭解到了 Mutation 必須是同步函數,那麼如果需求當中必須要用到非同步函數怎麼辦?
好辦,那就輪到 Action 上場了。
簡單介紹
Action 類似於 mutation,不同在於:
1、Action 提交的是 mutation,而不是直接變更狀態。
2、Action 可以包含任意非同步操作。
看一個簡單的 action 示例:
const store = new Vuex.Store({
state: {
count: 0
},
mutations: {
increment (state) {
state.count++
}
},
actions: {
increment (context) {
context.commit('increment')
}
}
})
可以看到,Action 函數接受一個 context
參數,註意,這個參數可不一般,它與 store 實例有著相同的方法和屬性,但是他們並不是同一個實例,後面學習 Modules 的時候會介紹它們為什麼不一樣。
所以在這裡可以使用 context.commit
來提交一個 mutation
,或者通過 context.state
和 context.getters
來獲取 state 和 getters。
當然,為了代碼簡化,我們可以使用 ES2015 的 參數解構 來直接展開,便於 commit
、state
等多次調用。如下:
actions: {
increment ({ commit }) {
commit('increment')
}
}
分發 Action
store.dispatch('increment')
Mutation 通過 store.commit 觸發,那麼 Action 則通過 store.dispatch 方法觸發。
乍一眼看上去感覺多此一舉,我們直接分發 mutation 豈不更方便?實際上並非如此,還記得 mutation 必須同步執行這個限制麽?Action 就不受約束!我們可以在 action 內部執行非同步操作:
actions: {
incrementAsync ({ commit }) {
setTimeout(() => {
commit('increment')
}, 1000)
}
}
和 Mutation 分發的方式異曲同工,這是註意這裡是 dispatch
:
// 以載荷形式分發
store.dispatch('incrementAsync', {
amount: 10
})
// 以對象形式分發
store.dispatch({
type: 'incrementAsync',
amount: 10
})
來看一個更加實際的購物車示例,涉及到調用非同步 API 和分發多重 mutation:
actions: {
checkout ({ commit, state }, products) {
// 把當前購物車的物品備份起來
const savedCartItems = [...state.cart.added]
// 發出結賬請求,然後樂觀地清空購物車
commit(types.CHECKOUT_REQUEST)
// 購物 API 接受一個成功回調和一個失敗回調
shop.buyProducts(
products,
// 成功操作
() => commit(types.CHECKOUT_SUCCESS),
// 失敗操作
() => commit(types.CHECKOUT_FAILURE, savedCartItems)
)
}
}
註意示例中正在進行一系列的非同步操作,並且通過提交 mutation 來記錄 action 產生的副作用(即狀態變更)。
組合 Action
Action 通常是非同步的,那麼如何知道 action 什麼時候結束呢?更重要的是,我們如何才能組合多個 action,以處理更加複雜的非同步流程?首先,你需要明白
store.dispatch
可以處理被觸發的 action 的處理函數返回的 Promise,並且store.dispatch
仍舊返回 Promise:
不知道什麼是 Promise 的,可以 戳此瞭解下。
actions: {
actionA ({ commit }) {
return new Promise((resolve, reject) => {
setTimeout(() => {
commit('someMutation')
resolve()
}, 1000)
})
}
}
調用:
store.dispatch('actionA').then(() => {
// ...
})
當然,也可以這樣:
actions: {
// ...
actionB ({ dispatch, commit }) {
return dispatch('actionA').then(() => {
commit('someOtherMutation')
})
}
}
我們還可以利用 async / await 的方式組合 action :
// 假設 getData() 和 getOtherData() 返回的是 Promise
actions: {
async actionA ({ commit }) {
commit('gotData', await getData())
},
async actionB ({ dispatch, commit }) {
await dispatch('actionA') // 等待 actionA 完成
commit('gotOtherData', await getOtherData())
}
}
一個
store.dispatch
在不同模塊中可以觸發多個 action 函數。在這種情況下,只有當所有觸發函數完成後,返回的 Promise 才會執行。
我們在實際項目中經常的會遇到這種情況,比如說你現在想要處理 B 事件,但是 B 事件需要一種資源才能進行,而這種資源必須通過 A 事件來獲得。這個時候,我們就需要組合 Action 來處理這些事件了。
寫在最後
這一講官方講解得非常清晰,基本上沒啥難理解的,所以大部分都是直接引用了。當然,有任何的疑問都可以在下方留言和我一起溝通討論,謝謝!
轉載聲明:
作者:大巨集說
鏈接:https://www.jianshu.com/p/7238d4d42725
後記
以上就是胡哥今天給大家分享的內容,喜歡的小伙伴記得點贊
、收藏
呦,關註胡哥有話說,學習前端不迷路,歡迎多多留言交流...
胡哥有話說,一個有技術,有情懷的胡哥!現任京東前端攻城獅一枚。
胡哥有話說,專註於大前端技術領域,分享前端系統架構,框架實現原理,最新最高效的技術實踐!