手撕Vuex-實現mutations方法

BNTang發表於2023-10-31

經過上一篇章介紹,完成了實現 getters 的功能,那麼接下來本篇將會實現 mutations 的功能。

在實現之前我們先來回顧一下 mutations 的使用。

將官方的 Vuex 匯入進來,因為我們的還沒有實現,現用一下官方的,來演示一下 mutations 的使用。

mutations 是用來修改共享資料的,先在 mutations 中定義一個方法,這個方法接受兩個引數,第一個引數是 state,第二個引數是 payload,payload 是一個物件,這個物件中存放的是我們需要修改的資料。

addNum(state, payload) {
    state.num += payload;
},

在 state 當中定義 num:

接下來就是使用了,使用的時候需要使用 commit 方法,commit 方法接受兩個引數,第一個引數是方法名,第二個引數是 payload,payload 是一個物件,這個物件中存放的是我們需要修改的資料。

隨便找一個元件,先展示我們的 num,然後在編寫一個按鈕,點選按鈕之後呼叫 addNum 方法,傳入一個引數 10,這樣就可以實現 num 的增加了。

展示 num,我這裡在 HelloWorld.vue 元件中進行展示的:

<template>
  <div class="hello">
    <p>{{ this.$store.state.num }}</p>
  </div>
</template>

展示完畢之後在編寫一個按鈕,點選按鈕之後呼叫 addNum 方法:

<button @click="myFn">我是按鈕</button>

在 HelloWorld.vue 元件中編寫 myFn 方法:

myFn() {
  this.$store.commit('addNum', 10);
},

好了到這裡,我們的基本結構搭建完畢,執行一下,看看效果:

這個就是 mutations 的基本使用,那麼瞭解完和回顧完畢之後,接下來我們就來實現 mutations 的功能。

其實 mutations 的實現和 getters 的實現差不多,好,我們廢話不多說,直接來處理下吧,我先將上一篇處理 getters 的程式碼封裝下,然後再來處理 mutations 的程式碼。

我單獨抽取一個 initGetters 來做這個事情,這樣程式碼就清晰了很多,這個 initGetters 方法接受一個 options,然後在將之前處理的程式碼放進去即可。

程式碼如下:

constructor(options) {
    this.state = options.state;
    // 將傳遞進來的 getters 放到 Store 上
    this.initGetters(options);
}

initGetters(options) {
    // 1.拿到傳遞進來的getters
    let getters = options.getters || {};
    // 2.在Store上新增一個getters的屬性
    this.getters = {};
    // 3.將傳遞進來的getters中的方法新增到當前Store的getters上
    for (let key in getters) {
        Object.defineProperty(this.getters, key, {
            get: () => {
                // 4.將getters中的方法執行, 並且將state傳遞過去
                return getters[key](this.state);
            }
        })
    }
}

這樣我們的 getters 就處理完畢了,接下來我們就來處理 mutations 的程式碼。

一樣的我編寫一個 initMutations 方法,這個方法接受一個 options, 這裡的步驟和 getters 的步驟是一樣的,我們先來看一下程式碼:

initMutations(options) {
    // 1.拿到傳遞進來的mutations
    let mutations = options.mutations || {};
    // 2.在Store上新增一個mutations的屬性
    this.mutations = {};
    // 3.將傳遞進來的mutations中的方法新增到當前Store的mutations上
    for (let key in mutations) {
        this.mutations[key] = (payload) => {
            mutations[key](this.state, payload);
        }
    }
}

這樣 Store 上面就有了一個 mutations 的屬性,這個屬性中存放的是我們傳遞進來的 mutations 方法,先來驗證一下,開啟瀏覽器,看看效果:

注意點:記得將官方的 Vuex 註釋掉,用我們自己的 Nuex。

這樣我們的 mutations 就處理完畢了,接下來我們就來處理一下 commit 方法。

透過之前我們在使用 mutations 的時候,是透過 store.commit 方法來呼叫的,所以我們需要在 Store 上面新增一個 commit 方法,這個方法接受兩個引數,第一個引數是方法名,第二個引數是 payload,payload 是一個物件,這個物件中存放的是我們需要修改的資料。

commit 方法具體的實現程式碼邏輯就是去 mutations 中找到對應的方法,然後執行這個方法,將 state 和 payload 傳遞過去。

程式碼如下:

commit(type, payload) {
    this.mutations[type](payload);
}

實現了 commit 方法之後,我們就可以在元件中使用了,我們先來驗證一下,開啟瀏覽器,看看效果:

我這裡不截圖了,效果就是點選了按鈕發現 num 值並沒有發生變化,這是為什麼呢?

因為我們在 mutations 中修改的是 state 當中的資料,state 並沒有實現雙向繫結,所以不改變是正常的。

那麼在 mutations 中更改了 state 的資料之後,我們怎麼去更新檢視呢?這裡我們只需要將 state 變成雙向繫結的即可,這裡我們使用 Vue 當中的 util 工具類來進行快速實現雙向繫結。

正好呢透過這個問題,可以讓大家知道在 Vue 中的 util 工具類中提供了有一個方法叫做 defineReactive,這個方法可以讓我們的資料變成雙向繫結的。

透過這個方法就可以快速的將某個資料變成雙向繫結的資料,defineReactive 這個方法接收三個引數:

  • 第一個引數: 要給哪個物件新增屬性
  • 第二個引數: 要給指定的物件新增什麼屬性
  • 第三個引數: 要給這個屬性新增什麼值

好了,廢話不多說,我們直接來處理一下吧,我們先匯入 Vue,就可以透過 Vue.util.defineReactive 來呼叫這個方法了。

程式碼如下:

Vue.util.defineReactive(this, 'state', options.state);

本章的重點就是要知道在 Vue 當中有 defineReactive 方法,這個方法可以讓我們的資料變成雙向繫結的,這樣我們就可以在 mutations 中修改 state 的資料之後,檢視也會發生變化了。

這樣我們的 state 就變成了雙向繫結的了,驗證一下,開啟瀏覽器,看看效果即可,好了到這裡,我們的 mutations 就處理完畢了。

相關文章