Vuex 模塊化與項目實例 (2.0)


Vuex 強調使用單一狀態樹,即在一個項目里只有一個 store,這個 store 集中管理了項目中所有的數據以及對數據的操作行為。但是這樣帶來的問題是 store 可能會非常臃腫龐大不易維護,所以就需要對狀態樹進行模塊化的拆分。

 

首先貼出一個邏輯比較復雜的H5項目:源碼 & DEMO

該項目主要包括 banner、feeds、profile 三個部分。其中 feeds 模塊最復雜,需要對數據列表進行處理,如果單條數據中是圖片:1張按照屏幕寬展示;2張各占50%;3張以上采用九宮格形式展示;如果單條數據是視頻,則顯示播放按鈕,播放一條視頻時,其他視頻暫停。

由於該項目數據、交互較多,我們使用 Vuex 對數據進行托管,只在 Vue 組件中保留最基本的操作。

如果不使用 Vuex,許多數據流需要通過 props 的方便向下傳遞,十分不便,尤其是一些跨組件的操作更加困難。使用 Vuex 后就可以將數據與操作保留在 store 中,每個組件都能輕松調用。

本項目中除了根 store 以外,還通過 module 將各組件的 store 分開管理,還不了解的同學可以往下看。

 

Module

首先介紹下基本的組件化規則:你可以根據項目組件的划分來拆分 store,每個模塊里管理着當前組件的狀態以及行為,最后將這些模塊在根 store 進行組合。

const moduleA = {
    state: { ... },
    getters: { ... }
    mutations: { ... }
};

const moduleB = {
    state: { ... },
    getters: { ... },
    mutations: { ... },
    actions: { ... }
};

const store = new Vuex.Store({
    modules: {
        a: moduleA,
        b: moduleB
    }
});

console.log(store.state.a); // moduleA 的 state

接下來看 Vuex 核心在模塊化后的使用注意事項。

請參考上文 Vuex 核心知識 (2.0)

 

State

在 Vuex 模塊化中,state 是唯一會根據組合時模塊的別名來添加層級的,后面的 getters、mutations 以及 actions 都是直接合並在 store 下。

例如,訪問模塊 a 中的 state,要通過 store.state.a,訪問根 store 上申明的 state,依然是通過 store.state.xxx 直接訪問。

const moduleA = {
    state: {
        maState: 'A'
    }
};

const moduleB = {
    state: {
        mbState: 'B'
    }
};

const store = new Vuex.Store({
    modules: {
        a: moduleA,
        b: moduleB
    },
    state: {
        rtState: 'Root'
    }
});

console.log(store.state.a.maState); // A
console.log(store.state.b.mbState); // B
console.log(store.state.rtState); // Root

 

Getters

與 state 不同的是,不同模塊的 getters 會直接合並在 store.getters 下

const moduleA = {
    state: {
        count: 1
    },
    getters: {
        maGetter(state, getters, rootState) {
            return state.count + rootState.b.count;
        }
    }
};

const moduleB = {
    state: {
        count: 2
    },
    getters: {
        mbGetter() {
            return 'Hello Vuex';
        }
    }
};

const store = {
    modules: {
        a: moduleA,
        b: moduleB
    }
};

console.log(store.getters.maGetter); // 3
console.log(store.getters.mbGetter); // Hello Vuex

在上文我們介紹過 getters 的回調函數所接收的前兩個參數,模塊化后需要用到第三個參數——rootState。參數: 1. state,模塊中的 state 僅為模塊自身中的 state;2. getters,等同於 store.getters;3. rootState,全局 state。

通過 rootState,模塊中的 getters 就可以引用別的模塊中的 state 了,十分方便。

注意:由於 getters 不區分模塊,所以不同模塊中的 getters 如果重名,Vuex 會報出 'duplicate getter key: [重復的getter名]' 錯誤。

 

Mutations

mutations 與 getters 類似,不同模塊的 mutation 均可以通過 store.commit 直接觸發。

const moduleA = {
    state: {
        count: 1
    },
    mutations: {
        sayCountA(state) {
            console.log('Module A count: ', state.count);
        }
    }
};

const moduleB = {
    state: {
        count: 2
    },
    mutations: {
        sayCountB(state) {
            console.log('Module B count: ', state.count);
        }
    }
};

const store = {
    modules: {
        a: moduleA,
        b: moduleB
    }
};

store.commit('sayCountA'); // Module A count: 1
store.commit('sayCountB'); // Module B count: 2 

mutation 的回調函數中只接收唯一的參數——當前模塊的 state。如果不同模塊中有同名的 mutation,Vuex 不會報錯,通過 store.commit 調用,會依次觸發所有同名 mutation。

 

Actions

與 mutations 類似,不同模塊的 actions 均可以通過 store.dispatch 直接觸發。

const moduleA = {
    state: {
        count: 1
    },
    mutations: {
        sayCountA(state) {
            console.log('Module A count: ', state.count);
        }
    },
    actions: {
        maAction(context) {
            context.dispatch('mbAction');
        }
    }
};

const moduleB = {
    state: {
        count: 2
    },
    mutations: {
        sayCountB(state, num) {
            console.log('Module B count: ', state.count+num);
        }
    },
    action: {
        mbAction({ commit, rootState }) {
            commit('sayCountA');
            commit('sayCountB', rootState.a.count);
        }
    }
};

const store = {
    modules: {
        a: moduleA,
        b: moduleB
    }
};

store.dispatch('maAction'); // Module A count: 1、Module B count: 3

從上例可以看出,action 的回調函數接收一個 context 上下文參數,context 包含:1. state、2. rootState、3. getters、4. mutations、5. actions 五個屬性,為了簡便可以在參數中解構。

在 action 中可以通過 context.commit 跨模塊調用 mutation,同時一個模塊的 action 也可以調用其他模塊的 action。

同樣的,當不同模塊中有同名 action 時,通過 store.dispatch 調用,會依次觸發所有同名 actions。

 

最后有一點要注意的是,將 store 中的 state 綁定到 Vue 組件中的 computed 計算屬性后,對 state 進行更改需要通過 mutation 或者 action,在 Vue 組件中直接進行賦值 (this.myState = 'ABC') 是不會生效的。

 

感謝你的瀏覽,希望能有所幫助。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM