手撕Vuex-安裝模組方法

2023-11-18 12:00:11

前言

經過上一篇文章的介紹,我們實現了將模組安裝到 store 中,那麼本章我們就來介紹一下怎麼安裝模組當中的方法也就是 actions、mutations、getters。

所以本次文章的目標就是將模組當中的 actions、mutations、getters 安裝到 store 中,然後在元件中使用。

分析階段

那麼安裝 actions、mutations、getters 就不能在 Store 的建構函式進行呼叫安裝方法進行安裝了。

為什麼呢,因為你在使用建構函式進行呼叫安裝方法是拿不到我們的子模組的,所以我們該怎麼改造呢?

首先我將這三個 init 方法剪下了:

然後我們是不是可以在 installModule 方法當中進行安裝呢?

我的回答是可以的,我們可以在 installModule 方法當中進行安裝。

我們在 initModule 方法當中遍歷取出了所有的子模組,在這個方法中我們就可以拿到所有的子模組,所以說我覺得在這裡安裝 actions、mutations、getters 是最好的,更為合適的。

程式碼實現

那麼我們該給 initActions、initMutations、initGetters 傳遞什麼引數呢?之前傳遞的是 options 選項,現在我們傳遞的是 module 模組,因為我們在 installModule 方法當中已經拿到了 module 模組,所以我們直接將 module 模組傳遞給 initActions、initMutations、initGetters 就可以了。

當前模組儲存到了當前傳遞進來引數的 _raw 屬性上面,改造之後的程式碼如下:

由於增加了我們的一個子模組所以,我們的 initActions、initMutations、initGetters 方法是需要進行微調的,首先我們來微調 initGetters 方法,由於這個方法會被多次呼叫,所以說我們首先進入到方法當中進行分析,在 getters 當中由於它多次被呼叫,是不是說新增過了 getters 就不需要再次新增了,所以說我們需要判斷一下,如果說當前的 getters 已經存在了,那麼就不需要再次新增了,如果說當前的 getters 不存在,那麼就需要新增。改造之後的程式碼如下:

邏輯非常的簡單,就是如果有就返回,沒有就返回一個空物件,這個呢就是我們 getters 需要做的改變。

然後呢,我們在來看一下 actions 和 mutations,這兩個方法有什麼改變,和剛才一樣,由於它會被多次呼叫,所以說在 mutations 當中,如果說當前的 mutations 已經存在了,那麼就不需要再次新增了,如果說當前的 mutations 不存在,那麼就需要新增。改造之後的程式碼如下:

actions 同理可證一樣的邏輯,自己新增一下別忘記了,不然會導致 "TypeError: Cannot read properties of undefined (reading 'forEach')" 會重新開闢一個新的 actions 所以就不會按照我之前分析的思路去走邏輯了,建立了 mutations 之後,在之前的文章當中我有介紹到,mutations 與 actions 當中的方法是可以重複的,也就是說在子模組當中定義的方法是不會覆蓋掉根模組當中的方法的,所以說我們在這裡需要將子模組當中的方法與根模組當中的方法進行合併,合併之後的方法是一個陣列,然後在執行這個陣列當中的方法,這樣就可以了。

所以我們要改造的就是在新增方法的時候進行改造程式碼,首先我們拿到對應名稱的方法,先去獲取一下看看有沒有對應名稱的方法,看看有沒有,如果說沒有,我們就返回一個空陣列,後續就是用這個陣列來儲存同名的方法,那這裡改為了用陣列來儲存同名的方法,那麼就不是直接賦值了,這裡應該改造為往這個名稱的陣列當中新增方法,改造之後的程式碼如下:

// 2.在Store上新增一個mutations的屬性
this.mutations = this.mutations || {};
// 3.將傳遞進來的mutations中的方法新增到當前Store的mutations上
for (let key in mutations) {
    this.mutations[key] = this.mutations[key] || [];
    this.mutations[key].push((payload) => {
        // 4.將mutations中的方法執行, 並且將state傳遞過去
        mutations[key](this.state, payload);
    });
}

actions 同理可證,改造之後的程式碼如下:

好了到這裡還沒完,我們目前已經將所有的方法放入到陣列當中了,那麼以後我們怎麼執行這一步我們是不是還需要改造一下,我們在 commit 的時候,我們是不是需要將這個陣列當中的方法執行一下,那麼我們就需要改造一下 commit 方法,改造之後的程式碼如下:

commit = (type, payload) => {
    this.mutations[type].forEach(fn => fn(payload));
}

dispatch 方法也是一樣的,改造之後的程式碼如下:

dispatch = (type, payload) => {
    this.actions[type].forEach(fn => fn(payload));
}

測試

好了到這裡我們的程式碼就改造完畢了,我們來找一個元件來測試一下,將我們之前的測試共用資料的註釋程式碼放開,頁面效果如下:

發現 getters 是 undefined,好了我們回到程式碼來看看到底是怎麼回事引起的,找到我們的 getters,發現我們給的 state 是不對的,我們應該將當前模組的 state 傳遞進去,改造之後的程式碼如下:

return getters[key](options.state);

重新整理頁面就會發現已經好了,那麼我們的 actions 和 mutations 也是一樣的:

mutations[key](options.state, payload);

actions 沒有用到所以這裡我們就不用管它。好了到這裡我覺得我編寫的程式碼已經沒有問題了,我們來看一下頁面效果,這裡我錄製一個 gif 圖片,方便大家觀看:

最後