經過上一篇章介紹,完成了實現 mutations 的功能,那麼接下來本篇將會實現 actions 的功能。
本篇我先介紹一下 actions 的作用,然後再介紹一下實現的思路,最後再實現程式碼。
actions 的作用是用來非同步修改共享資料的,怎麼非同步修改,這個時候我們回到 Vue 的官方 Vuex 文件中,有如下這麼一個圖:
從圖中可以看出,我們在元件中呼叫 dispatch 方法,然後 dispatch 方法會呼叫 actions,然後 actions 中的方法可以透過 commit 會呼叫 mutations 中的方法,最後 mutations 中的方法會修改 state 中的資料,這就是 actions 的作用。
這裡我們先來回顧一下怎麼使用 actions,再來實現一遍即可。
- 將官方的 Vuex 註釋放開
- 在 store 中定義 age
- 在 mutations 中定義 changeAge 方法
- 在 actions 中定義 asyncAddAge 方法 (頁面透過 dispatch 呼叫 actions 中的方法, actions 中的方法透過 commit 呼叫 mutations 中的方法)
如上是我本次實現的思路,接下來我們來實現程式碼。
我這裡直接貼出程式碼, 程式碼中有詳細的註釋, 程式碼如下:
1. 略過
2. 定義 age
state: {
age: 0
}
3. 在 mutations 中定義 changeAge 方法
/**
* 透過dispatch呼叫
* @param state 倉庫的state
* @param payload 載荷
*/
addAge(state, payload) {
state.age += payload;
}
4. 在 actions 中定義 asyncAddAge 方法
/**
* 透過dispatch呼叫
* @param commit 提交
* @param payload 載荷
*/
asyncAddAge({commit}, payload) {
// 模擬非同步操作
setTimeout(() => {
// 透過commit呼叫mutations中的方法
commit('addAge', payload);
}, 3000);
}
- 在元件中透過 dispatch 呼叫 actions 中的方法(HelloWorld 元件)
// 顯示資料
<p>{{ this.$store.state.age }}</p>
// 呼叫actions中的方法
<button @click="myFn">我是按鈕</button>
myFn() {
this.$store.dispatch('asyncAddAge', 10);
},
npm run serve 啟動專案,點選按鈕,3 秒後 age 的值加 10,說明 actions 的功能實現了。效果如下圖:
到此為止,回顧完成了之後,我們就可以開始實現 actions 的功能了。
actions 的實現思路和 mutations 的實現思路是一樣的,首先將官方的 Vuex 註釋掉,匯入我們自己的 Nuex:
import Vuex from './Nuex'
// import Vuex from 'vuex'
回到我們的 Nuex 檔案中,和之前一樣先將 actions 儲存到 Store 上,我這裡單獨弄了一個 initActions
方法,程式碼如下:
// 將傳遞進來的 actions 放到 Store 上
this.initActions(options);
initActions 方法的實現如下:
initActions(options) {
// 1.拿到傳遞進來的actions
let actions = options.actions || {};
// 2.在Store上新增一個actions的屬性
this.actions = {};
// 3.將傳遞進來的actions中的方法新增到當前Store的actions上
for (let key in actions) {
this.actions[key] = (payload) => {
// 4.將actions中的方法執行, 並且將當前Store例項傳遞過去
actions[key](this, payload);
}
}
}
這裡和 mutations 的實現思路是一樣的,只是將 mutations 換成了 actions,然後將傳遞進來的 actions 中的方法新增到當前 Store 的 actions 上,最後將 actions 中的方法執行,並且將當前 Store 例項傳遞過去。
測試一下看看有沒有新增到 Store 上,執行專案,測試結果如下:
可以看到 actions 已經新增到 Store 上了,那麼在頁面上是透過 dispatch 呼叫 actions 中的方法,所以我們需要在 Store 上新增 dispatch 方法,程式碼如下:
dispatch = (type, payload) => {
this.actions[type](payload);
}
這裡和 mutations 的實現思路是一樣的,只是將 commit 換成了 actions,然後將傳遞進來的 actions 中的方法執行,並且將當前 Store 例項傳遞過去。
執行專案,測試結果如下:
Uncaught TypeError: Cannot read properties of undefined (reading 'mutations')
這裡報錯了,其實這個問題我已經知道錯在哪裡了,我先帶著大家看一下這個呼叫流程,然後再解決這個問題。
- 在元件中呼叫 dispatch 方法,我傳遞是的
'asyncAddAge', 10
- 在 dispatch 方法中,我拿到了傳遞進來的 type,也就是
'asyncAddAge'
, payload 也就是 10, 然後呼叫了 actions 中的方法
- 在 actions 中的方法中,我拿到了傳遞進來的 payload,也就是 10,在 asyncAddAge 方法中,我呼叫了 commit 方法,也就是呼叫了 mutations 中的方法
- 在 commit 方法中,我拿到了傳遞進來的 type,也就是
'addAge'
, payload 也就是 10, 然後呼叫了 mutations 中的方法
報錯的位置在這裡,因為我在 commit 方法中,拿到了傳遞進來的 type,也就是 'addAge'
, 程式碼繼續往下執行,執行到 this.mutations[type](payload);
this 是 undefined,所以報錯了。
正是因為在 actions 中的方法中,我呼叫了 commit 方法,也就是呼叫了 mutations 中的方法,在呼叫時沒有告訴 commit 方法,this 是誰,所以才會報錯。
那麼怎麼解決這個問題呢?其實很簡單,只需要將之前的 commit 方法改為箭頭函式即可,因為改為了箭頭函式,this 就是當前 Store 例項了(改為了箭頭函式當前在哪裡定義的那麼 this 就是誰),程式碼如下:
commit = (type, payload) => {
this.mutations[type](payload);
}
執行專案,測試結果如下:
到此為止,actions 的功能就實現了,接下來我們來回顧一下實現的思路。
- 將傳遞進來的 actions 放到 Store 上
- 在 Store 上新增 dispatch 方法
- 在 dispatch 方法中,呼叫 actions 中的方法
- 在 actions 中的方法中,呼叫 commit 方法
- 在 commit 方法中,呼叫 mutations 中的方法(這裡就走我們上一篇章的流程了)