Vuex的五個(gè)核心屬性

Vuex的五個(gè)核心概念

本文參考自Vue文檔,說的非常詳細(xì),建議看文檔。

Vuex是什么?

VueX 是一個(gè)專門為 Vue.js 應(yīng)用設(shè)計(jì)的狀態(tài)管理架構(gòu),統(tǒng)一管理和維護(hù)各個(gè)vue組件的可變化狀態(tài)(你可以理解成 vue 組件里的某些 data )。

Vue有五個(gè)核心概念,state,getters,mutations,actions,modules。本文將對這個(gè)五個(gè)核心概念進(jìn)行梳理。

總結(jié)

state => 基本數(shù)據(jù)

getters => 從基本數(shù)據(jù)派生的數(shù)據(jù)

mutations => 提交更改數(shù)據(jù)的方法,同步!

actions => 像一個(gè)裝飾器,包裹mutations,使之可以異步。

modules => 模塊化Vuex

State

state即Vuex中的基本數(shù)據(jù)!

單一狀態(tài)樹

Vuex使用單一狀態(tài)樹,即用一個(gè)對象就包含了全部的狀態(tài)數(shù)據(jù)。state作為構(gòu)造器選項(xiàng),定義了所有我們需要的基本狀態(tài)參數(shù)。

在Vue組件中獲得Vuex屬性

我們可以通過Vue的Computed獲得Vuex的state,如下:

const store =new Vuex.Store({

? ? state: {

? ? ? ? count:0? ? }

})

const app =new Vue({

? ? //..? ? store,

? ? computed: {

? ? ? ? count: function(){

? ? ? ? ? ? returnthis.$store.state.count

? ? ? ? }

? ? },

? ? //..})

每當(dāng)store.state.count變化的時(shí)候, 都會重新求取計(jì)算屬性,并且觸發(fā)更新相關(guān)聯(lián)的 DOM。

mapState輔助函數(shù)

當(dāng)一個(gè)組件需要獲取多個(gè)狀態(tài)時(shí)候,將這些狀態(tài)都聲明為計(jì)算屬性會有些重復(fù)和冗余。為了解決這個(gè)問題,我們可以使用 mapState 輔助函數(shù)幫助我們生成計(jì)算屬性,讓你少按幾次鍵。

// 在單獨(dú)構(gòu)建的版本中輔助函數(shù)為 Vuex.mapStateimport { mapState } from 'vuex'export default {

? // ...? computed: mapState({

? ? // 箭頭函數(shù)可使代碼更簡練count: state => state.count,

? ? // 傳字符串參數(shù) 'count' 等同于 `state => state.count`countAlias: 'count',

? ? // 為了能夠使用 `this` 獲取局部狀態(tài),必須使用常規(guī)函數(shù)? ? countPlusLocalState (state) {

? ? ? returnstate.count +this.localCount

? ? }

? })

}

當(dāng)映射的計(jì)算屬性的名稱與 state 的子節(jié)點(diǎn)名稱相同時(shí),我們也可以給 mapState 傳一個(gè)字符串?dāng)?shù)組。

computed: mapState([

? // 映射 this.count 為 store.state.count'count'])

對象展開運(yùn)算符

mapState 函數(shù)返回的是一個(gè)對象。我們?nèi)绾螌⑺c局部計(jì)算屬性混合使用呢?通常,我們需要使用一個(gè)工具函數(shù)將多個(gè)對象合并為一個(gè),以使我們可以將最終對象傳給 computed 屬性。但是自從有了對象展開運(yùn)算符,我們可以極大地簡化寫法:

computed: {

? localComputed () //本地計(jì)算屬性//使用對象展開運(yùn)算符將此對象混入到外部對象中? ...mapState({

? ? //..? })

}

對象運(yùn)算符?

...展開運(yùn)算符(spread operator)允許一個(gè)表達(dá)式在某處展開。展開運(yùn)算符在多個(gè)參數(shù)(用于函數(shù)調(diào)用)或多個(gè)元素(用于數(shù)組字面量)或者多個(gè)變量(用于解構(gòu)賦值)的地方可以使用。

展開運(yùn)算符不能用在對象當(dāng)中,因?yàn)槟壳罢归_運(yùn)算符只能在可遍歷對象(iterables)可用。iterables的實(shí)現(xiàn)是依靠[Symbol.iterator]函數(shù),而目前只有Array,Set,String內(nèi)置[Symbol.iterator]方法,而Object尚未內(nèi)置該方法,因此無法使用展開運(yùn)算符。不過ES7草案當(dāng)中已經(jīng)加入了對象展開運(yùn)算符特性。

function test(a,b,c) {

? ? ? ? console.log(a);

? ? ? ? console.log(b);

? ? ? ? console.log(c);

? ? }

? ? varargs = [0,1,2];

? ? test(...args);? // 0? 1? 2

ES7草案中的對象展開運(yùn)算符?

ES6中還不支持對對象的展開運(yùn)算符,但是ES7中將支持。對象展開運(yùn)算符符可以讓我們更快捷地操作對象,如下例子:

let {x,y,...z}={x:1,y:2,a:3,b:4};

? ? x; //1y;//2z;//{a:3,b:4}

組件仍然保有局部狀態(tài)

使用 Vuex 并不意味著你需要將所有的狀態(tài)放入 Vuex。雖然將所有的狀態(tài)放到 Vuex 會使?fàn)顟B(tài)變化更顯式和易調(diào)試,但也會使代碼變得冗長和不直觀。

如果有些狀態(tài)嚴(yán)格屬于單個(gè)組件,最好還是作為組件的局部狀態(tài)。你應(yīng)該根據(jù)你的應(yīng)用開發(fā)需要進(jìn)行權(quán)衡和確定。

getters

即從store的state中派生出的狀態(tài)。

getters接收state作為其第一個(gè)參數(shù),接受其他 getters 作為第二個(gè)參數(shù),如不需要,第二個(gè)參數(shù)可以省略如下例子:

const store =new Vuex.Store({

? ? state: {

? ? ? ? count:0? ? },

? ? getters: {

? ? ? ? // 單個(gè)參數(shù)countDouble:function(state){

? ? ? ? ? ? returnstate.count * 2? ? ? ? },

? ? ? ? // 兩個(gè)參數(shù)countDoubleAndDouble:function(state, getters) {

? ? ? ? ? ? returngetters.countDouble * 2? ? ? ? }

? ? }

})

與state一樣,我們也可以通過Vue的Computed獲得Vuex的getters。

const app =new Vue({

? ? //..? ? store,

? ? computed: {

? ? ? ? count: function(){

? ? ? ? ? ? returnthis.$store.state.count

? ? ? ? },

? ? ? ? countDouble: function(){

? ? ? ? ? ? returnthis.$store.getters.countDouble

? ? ? ? },

? ? ? ? countDoubleAndDouble: function(){

? ? ? ? ? ? returnthis.$store.getters.countDoubleAndDouble

? ? ? ? }

? ? },

? ? //..})

mapGetters 輔助函數(shù)

mapGetters 輔助函數(shù)僅僅是將 store 中的 getters 映射到局部計(jì)算屬性,與state類似

import { mapGetters } from 'vuex'export default {

? // ...? computed: {

? // 使用對象展開運(yùn)算符將 getters 混入 computed 對象中? ? ...mapGetters([

? ? ? 'countDouble',

? ? ? 'CountDoubleAndDouble',

? ? ? //..? ? ])

? }

}

如果你想將一個(gè) getter 屬性另取一個(gè)名字,使用對象形式:

mapGetters({

? // 映射 this.double 為 store.getters.countDoubledouble: 'countDouble'})

mutations

提交mutation是更改Vuex中的store中的狀態(tài)的唯一方法。

mutation必須是同步的,如果要異步需要使用action。

每個(gè) mutation 都有一個(gè)字符串的 事件類型 (type) 和 一個(gè) 回調(diào)函數(shù) (handler)。這個(gè)回調(diào)函數(shù)就是我們實(shí)際進(jìn)行狀態(tài)更改的地方,并且它會接受 state 作為第一個(gè)參數(shù),提交載荷作為第二個(gè)參數(shù)。(提交荷載在大多數(shù)情況下應(yīng)該是一個(gè)對象),提交荷載也可以省略的。

const store =new Vuex.Store({

? state: {

? ? count: 1? },

? mutations: {

? ? //無提交荷載? ? increment(state) {

? ? ? ? state.count++? ? }

? ? //提交荷載? ? incrementN(state, obj) {

? ? ? state.count += obj.n

? ? }

? }

})

你不能直接調(diào)用一個(gè) mutation handler。這個(gè)選項(xiàng)更像是事件注冊:“當(dāng)觸發(fā)一個(gè)類型為 increment 的 mutation 時(shí),調(diào)用此函數(shù)?!币獑拘岩粋€(gè) mutation handler,你需要以相應(yīng)的 type 調(diào)用 store.commit 方法:

//無提交荷載store.commit('increment')//提交荷載store.commit('incrementN', {

? ? n: 100? ? })

對象風(fēng)格的提交方式

我們也可以使用這樣包含 type 屬性的對象的提交方式。

store.commit({

? type: 'incrementN',

? n: 10})

Mutations 需遵守 Vue 的響應(yīng)規(guī)則

最好提前在你的 store 中初始化好所有所需屬性。

當(dāng)需要在對象上添加新屬性時(shí),你應(yīng)該

使用Vue.set(obj, 'newProp', 123), 或者

以新對象替換老對象。例如,利用對象展開運(yùn)算符我們可以這樣寫state.obj = {...state.obj, newProp: 123 }

mapMutations 輔助函數(shù)

與其他輔助函數(shù)類似,你可以在組件中使用 this.$store.commit(‘xxx’) 提交 mutation,或者使用 mapMutations 輔助函數(shù)將組件中的 methods 映射為 store.commit 調(diào)用(需要在根節(jié)點(diǎn)注入 store)。

import { mapMutations } from 'vuex'export default {

? //..? methods: {

? ? ...mapMutations([

? ? ? 'increment'// 映射 this.increment() 為 this.$store.commit('increment')? ? ]),

? ? ...mapMutations({

? ? ? add: 'increment'// 映射 this.add() 為 this.$store.commit('increment')? ? })

? }

}

actions

Action 類似于 mutation,不同在于:

Action 提交的是 mutation,而不是直接變更狀態(tài)。

Action 可以包含任意異步操作。

我們用如下例子來結(jié)束actions:

const store =new Vuex.Store({

? state: {

? ? count: 0? },

? mutations: {

? ? increment (state) {

? ? ? state.count++? ? }

? },

? actions: {

? ? increment (context) {

? ? ? setInterval(function(){

? ? ? ? context.commit('increment')

? ? ? }, 1000)

? ? }

? }

})

注意:Action 函數(shù)接受一個(gè)與 store 實(shí)例具有相同方法和屬性的 context 對象,因此你可以調(diào)用 context.commit 提交一個(gè) mutation,或者通過 context.state 和 context.getters 來獲取 state 和 getters。

分發(fā)actions

Action 通過store.dispatch方法觸發(fā):

store.dispatch('increment')

其他與mutations類似的地方

Actions 支持同樣的載荷方式和對象方式進(jìn)行分發(fā):

// 以載荷形式分發(fā)store.dispatch('incrementN', {

? n: 10})// 以對象形式分發(fā)store.dispatch({

? type: 'incrementN',

? n: 10})

mapActions輔助函數(shù)

你在組件中使用this.$store.dispatch('xxx')分發(fā) action,或者使用mapActions輔助函數(shù)將組件的 methods 映射為store.dispatch調(diào)用(需要先在根節(jié)點(diǎn)注入store):

import { mapActions } from 'vuex'export default {

? //..? methods: {

? ? ...mapActions([

? ? ? 'incrementN'//映射 this.incrementN() 為 this.$store.dispatch('incrementN')? ? ]),

? ? ...mapActions({

? ? ? add: 'incrementN'//映射 this.add() 為 this.$store.dispatch('incrementN')? ? })

? }

}

Modules

使用單一狀態(tài)樹,導(dǎo)致應(yīng)用的所有狀態(tài)集中到一個(gè)很大的對象。但是,當(dāng)應(yīng)用變得很大時(shí),store 對象會變得臃腫不堪。

為了解決以上問題,Vuex 允許我們將 store 分割到模塊(module)。每個(gè)模塊擁有自己的 state、mutation、action、getters、甚至是嵌套子模塊——從上至下進(jìn)行類似的分割:

const moduleA = {

? state: { ... },

? mutations: { ... },

? actions: { ... },

? getters: { ... }

}

const moduleB = {

? state: { ... },

? mutations: { ... },

? actions: { ... }

}

const store =new Vuex.Store({

? modules: {

? ? a: moduleA,

? ? b: moduleB

? }

})

store.state.a // -> moduleA 的狀態(tài)store.state.b// -> moduleB 的狀態(tài)

模塊的局部狀態(tài)

對于模塊內(nèi)部的mutation和getter,接收的第一個(gè)參數(shù)是模塊的局部狀態(tài),對于模塊內(nèi)部的 getter,根節(jié)點(diǎn)狀態(tài)會作為第三個(gè)參數(shù):

const moduleA = {

? state: { count: 0 },

? mutations: {

? ? increment (state) {

? ? ? // state 模塊的局部狀態(tài)state.count++? ? }

? },

? getters: {

? ? doubleCount (state) {

? ? ? returnstate.count * 2? ? },

? ? sumWithRootCount (state, getters, rootState) {

? ? ? returnstate.count + rootState.count

? ? }

? }

}

同樣,對于模塊內(nèi)部的 action,context.state是局部狀態(tài),根節(jié)點(diǎn)的狀態(tài)是context.rootState:

const moduleA = {

? // ...? actions: {

? ? incrementIfOddOnRootSum (context) {

? ? ? if((context.state.count + context.rootState.count) % 2 === 1) {

? ? ? ? commit('increment')

? ? ? }

? ? }

? }

}

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

  • 安裝 npm npm install vuex --save 在一個(gè)模塊化的打包系統(tǒng)中,您必須顯式地通過Vue.u...
    蕭玄辭閱讀 3,049評論 0 7
  • ### store 1. Vue 組件中獲得 Vuex 狀態(tài) ```js //方式一 全局引入單例類 // 創(chuàng)建一...
    蕓豆_6a86閱讀 789評論 0 3
  • Vuex是什么? Vuex 是一個(gè)專為 Vue.js應(yīng)用程序開發(fā)的狀態(tài)管理模式。它采用集中式存儲管理應(yīng)用的所有組件...
    蕭玄辭閱讀 3,238評論 0 6
  • ### store 1. Vue 組件中獲得 Vuex 狀態(tài) ```js //方式一 全局引入單例類 // 創(chuàng)建一...
    蕓豆_6a86閱讀 444評論 0 0
  • Vuex 的學(xué)習(xí)記錄 資料參考網(wǎng)址Vuex中文官網(wǎng)Vuex項(xiàng)目結(jié)構(gòu)示例 -- 購物車Vuex 通俗版教程N(yùn)uxt....
    流云012閱讀 1,543評論 0 7

友情鏈接更多精彩內(nèi)容