Vuex用法總結(jié)

1. Vuex簡(jiǎn)介

Vuex是專門(mén)用來(lái)管理vue.js應(yīng)用程序中狀態(tài)的一個(gè)插件只冻。他的作用是將應(yīng)用中的所有狀態(tài)都放在一起朴译,集中式來(lái)管理。需要聲明的是莫湘,這里所說(shuō)的狀態(tài)指的是vue組件中data里面的屬性倾鲫。

2. vuex的組成結(jié)構(gòu)示意圖

image.png

3. vuex 的核心概念

  • 一個(gè)完整的store的結(jié)構(gòu)是這樣的
const store = new Vuex.Store({
  state: {
    // 存放狀態(tài)
  },
  getters: {
    // state的計(jì)算屬性
  },
  mutations: {
    // 更改state中狀態(tài)的邏輯粗合,同步操作
  },
  actions: {
    // 提交mutation,異步操作
  },
  // 如果將store分成一個(gè)個(gè)的模塊的話乌昔,則需要用到modules隙疚。
   //然后在每一個(gè)module中寫(xiě)state, getters, mutations, actions等。
  modules: {
    a: moduleA,
    b: moduleB,
    // ...
  }
});
  • vuex 中最關(guān)鍵的是store對(duì)象磕道,這是vuex的核心供屉。可以說(shuō),vuex這個(gè)插件其實(shí)就是一個(gè)store對(duì)象伶丐,每個(gè)vue應(yīng)用僅且僅有一個(gè)store對(duì)象悼做。

  • store是Vuex.Store這個(gè)構(gòu)造函數(shù)new出來(lái)的實(shí)例。在構(gòu)造函數(shù)中可以傳一個(gè)對(duì)象參數(shù)哗魂。這個(gè)參數(shù)中可以包含5個(gè)對(duì)象:

1.state – 存放狀態(tài)

2.getters – state的計(jì)算屬性

3.mutations – 更改狀態(tài)的邏輯肛走,同步操作

4.actions – 提交mutation,異步操作

5.mudules – 將store模塊化

  • 關(guān)于store录别,需要先記住兩點(diǎn):
  1. store 中存儲(chǔ)的狀態(tài)是響應(yīng)式的朽色,當(dāng)組件從store中讀取狀態(tài)時(shí),如果store中的狀態(tài)發(fā)生了改變组题,那么相應(yīng)的組件也會(huì)得到更新葫男;

  2. 不能直接改變store中的狀態(tài)。改變store中的狀態(tài)的唯一途徑是提交(commit)mutations崔列。這樣使得我們可以方便地跟蹤每一個(gè)狀態(tài)的變化梢褐。

3.1 state

state上存放的,說(shuō)的簡(jiǎn)單一些就是變量赵讯,也就是所謂的狀態(tài)盈咳。沒(méi)有使用 state 的時(shí)候,我們都是直接在 data 中進(jìn)行初始化的瘦癌,但是有了 state 之后猪贪,我們就把 data 上的數(shù)據(jù)轉(zhuǎn)移到 state 上去了跷敬。另外有些狀態(tài)是組件私有的狀態(tài)讯私,稱為組件的局部狀態(tài),我們不需要把這部分狀態(tài)放在store中去西傀。

3.2.1 如何在組件中獲取vuex狀態(tài)

由于vuex的狀態(tài)是響應(yīng)式的斤寇,所以從store中讀取狀態(tài)的的方法是在組件的計(jì)算屬性中返回某個(gè)狀態(tài)。

import store from 'store';
const Counter = {
template: <div>{{ count }}</div>,
computed: {
count () {
// 獲取store中的狀態(tài)
return store.state.count;
}
}
}
這樣拥褂,組件中的狀態(tài)就與store中的狀態(tài)關(guān)聯(lián)起來(lái)了娘锁。每當(dāng)store.state.count發(fā)生變化時(shí),都會(huì)重新求取計(jì)算屬性饺鹃,從而更新DOM莫秆。

然而,每個(gè)組件中都需要反復(fù)倒入store悔详∧魇海可以將store注入到vue實(shí)例對(duì)象中去,這樣每一個(gè)子組件中都可以直接獲取store中的狀態(tài)茄螃,而不需要反復(fù)的倒入store了缝驳。

const app = new Vue({
el: '#app',
// 把 store 對(duì)象注入到了
store,
components: { Counter },
template: <div> <counter></counter> </div>
});
這樣可以在子組件中使用this.$store.state.count訪問(wèn)到state里面的count這個(gè)狀態(tài)

const Counter = {
template: <div>{{ count }}</div>,
computed: {
count () {
// 獲取store中的狀態(tài)
return this.$store.state.count;
}
}
}

3.2.2 mapState

當(dāng)一個(gè)組件獲取多種狀態(tài)的時(shí)候,則在計(jì)算屬性中要寫(xiě)多個(gè)函數(shù)。為了方便用狱,可以使用mapState輔助函數(shù)來(lái)幫我們生成計(jì)算屬性运怖。

import { mapState } from 'vuex';
export default {
// ...
data (){
localState: 1
}
computed: mapState({
// 此處的state即為store里面的state
count: state => state.count,
// 當(dāng)計(jì)算屬性的名稱與state的狀態(tài)名稱一樣時(shí),可以省寫(xiě)
// 映射 this.count1 為 store.state.count1
count1,
//'count'等同于 ‘state => state.count’
countAlias: 'count',
countPlus (state){
// 使用普通函數(shù)是為了保證this指向組件對(duì)象
return state.count + this.localState;
}
})
}
//上面是通過(guò)mapState的對(duì)象來(lái)賦值的夏伊,還可以通過(guò)mapState的數(shù)組來(lái)賦值
computed: mapState(['count']);
//這種方式很簡(jiǎn)潔摇展,但是組件中的state的名稱就跟store中映射過(guò)來(lái)的同名
對(duì)象擴(kuò)展運(yùn)算符

mapState 函數(shù)返回的是一個(gè)對(duì)象,為了將它里面的計(jì)算屬性與組件本身的局部計(jì)算屬性組合起來(lái)署海,需要用到對(duì)象擴(kuò)展運(yùn)算符吗购。

computed: {
localState () {
...mapState ({
})
}
這樣,mapState中的計(jì)算屬性就與localState計(jì)算屬性混合一起了砸狞。

3.3 getters

有時(shí)候我們需要從 store 中的 state 中派生出一些狀態(tài)捻勉,例如對(duì)列表進(jìn)行過(guò)濾并計(jì)數(shù)。此時(shí)可以用到getters刀森,getters可以看作是store的計(jì)算屬性踱启,其參數(shù)為state。

const store = new Vuex.Store({
state: {
todos: [
{id: 1, text: 'reading', done: true},
{id: 2, text: 'playBastketball', done: false}
]
},
getters: {
doneTodos: state => {
return state.todos.filter(todo => todo.done);
}
}
});

3.3.1 獲取getters里面的狀態(tài)研底,方法一

store.getters.doneTodos // [{ id: 1, text: 'reading', done: true }]
//在組件中埠偿,則要寫(xiě)在計(jì)算屬性中,
computed: {
doneTodos () {
return this.$store.getters.doneTodos;
}
}

3.3.2 使用mapGetters獲取getters里面的狀態(tài):方法二

import {mapState, mapGetters} from 'vuex';
computed: {
...mapState(['increment']),
...mapGetters(['doneTodos'])
}

3.4 mutations

mutations里面是如何更改state中狀態(tài)的邏輯榜晦。更改Vuex中的state的唯一方法是冠蒋,提交mutation,即store.commit(‘increment’)乾胶。

3.4.1 提交載荷(payload)

可以向commit傳入額外的參數(shù)抖剿,即mutation的載荷。

mutations: {
increment(state, n){
state.count += n;
}
}
store.commit('increment', 10);
payload還可以是一個(gè)對(duì)象识窿。

mutations: {
increment(state, payload)
state.count += payload.amount;
}
}
store.commit('increment', {amount: 10});
還可以使用type屬性來(lái)提交mutation斩郎。

store.commit({
type: 'increment',
amount: 10
});
// mutations保持不變
mutations: {
increment(state, payload){
state.count += payload.amount;
}
}
注意:mutation必須是同步函數(shù),不能是異步的喻频,這是為了調(diào)試的方便缩宜。

3.4.2 在組件中提交mutations

那么mutation應(yīng)該在哪里提交呢? 因?yàn)閖s是基于事件驅(qū)動(dòng)的甥温,所以改變狀態(tài)的邏輯肯定是由事件來(lái)驅(qū)動(dòng)的锻煌,所以store.commit(‘increment’)是在組件的methods中來(lái)執(zhí)行的。

方法1: 在組件的methods中提交
methods: {
increment(){
this.$store.commit('increment');
}
}

方法2: 使用mapMutaions

用 mapMutations 輔助函數(shù)將組件中的 methods 映射為 store.commit 調(diào)用姻蚓。
import { mapMutaions } from 'vuex';
export default {
methods: {
...mapMutaions([
'increment' // 映射 this.increment() 為 this.store.commit('increment') ]), ...mapMutaions([ add: 'increment' // 映射 this.add() 為 this.store.commit('increment')
])
}
}

// 因?yàn)閙utation相當(dāng)于一個(gè)method宋梧,所以在組件中,可以這樣來(lái)使用
<button @click="increment">+</button>

3.5 actions

因?yàn)閙utations中只能是同步操作史简,但是在實(shí)際的項(xiàng)目中乃秀,會(huì)有異步操作肛著,那么actions就是為了異步操作而設(shè)置的。這樣跺讯,就變成了在action中去提交mutation枢贿,然后在組件的methods中去提交action。只是提交actions的時(shí)候使用的是dispatch函數(shù)刀脏,而mutations則是用commit函數(shù)局荚。

3.5.1 一個(gè)簡(jiǎn)單的action

const store = new Vuex.Store({
state: {
count: 0
},
mutations: {
increment(state){
state.count++;
}
},
actions: {
increment(context){
context.commit('increment');
}
/* 可以用參數(shù)結(jié)構(gòu)的方法來(lái)寫(xiě)action
increment({commit}){
commit('increment');
}
*/
}
});

// action函數(shù)接受一個(gè)context參數(shù),這個(gè)context具有與store實(shí)例相同的方法和屬性愈污。

// 分發(fā)action
store.dispatch('increment');
action同樣支持payload和對(duì)象方式來(lái)分發(fā)碟绑,格式跟commit是一樣的难裆,不再贅述。

3.5.2 在組件中分發(fā)action

方法1: 在組件的methods中,使用this.$store.dispatch(‘increment’)圈盔。

方法2: 使用mapActions授瘦,跟mapMutations是類似的二拐。

import { mapActions } from 'vuex'
export default {

methods: {
...mapActions([
'increment' // 映射 this.increment() 為 this.store.dispatch('increment') ]), ...mapActions({ add: 'increment' // 映射 this.add() 為 this.store.dispatch('increment')
})
}
}

// 同樣在組件中茂翔,可以這樣來(lái)使用
<button @click="increment">+</button>

3.5.3 組合actions

因?yàn)閍ction是異步的,那么我們需要知道這個(gè)異步函數(shù)什么時(shí)候結(jié)束涧尿,以及等到其執(zhí)行后系奉,會(huì)利用某個(gè)action的結(jié)果。這個(gè)可以使用promise來(lái)實(shí)現(xiàn)姑廉。在一個(gè)action中返回一個(gè)promise缺亮,然后使用then()回調(diào)函數(shù)來(lái)處理這個(gè)action返回的結(jié)果。

actions:{
actionA({commit}){
return new Promise((resolve, reject) => {
setTimeout(() => {
commit('someMutation');
resolve();
},1000);
})
}
}

// 這樣就可以操作actionA返回的結(jié)果了
store.dispatch('actionA').then(() => {
// dosomething ...
});

// 也可以在另一個(gè)action中使用actionA的結(jié)果
actions: {
actionB({ dispatch, commit }){
return dispatch('actionA').then(() => {
commit('someOtherMutation');
})
}
}

4 mudules

module是為了將store拆分后的一個(gè)個(gè)小模塊桥言,這么做的目的是因?yàn)楫?dāng)store很大的時(shí)候萌踱,分成模塊的話,方便管理限书。

4.1 每個(gè)module擁有自己的state, getters, mutation, action

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

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

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

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

4.2 模塊內(nèi)部的狀態(tài)

對(duì)于模塊內(nèi)部的mutation和getter虫蝶,接受的第一個(gè)參數(shù)是模塊的局部狀態(tài)state章咧。順便說(shuō)一下倦西,根結(jié)點(diǎn)的狀態(tài)為rootState。

const moduleA = {
state: { count: 0},
getters: {
doubleCount(state){
return state.count * 2;
}
},
mutations: {
increment(state){
state.count ++ ;
}
},
actions: {...}
}

4.3 模塊的動(dòng)態(tài)注冊(cè)

在模塊創(chuàng)建之后赁严,可以使用store.registerModule方法來(lái)注冊(cè)模塊扰柠。

store.registerModule('myModule', {
// ...
});
依然的,可以通過(guò)store.state.myModule來(lái)獲取模塊的狀態(tài)疼约。

可以使用store.unregisterModule(moduleName)來(lái)動(dòng)態(tài)的卸載模塊卤档,但是這種方法對(duì)于靜態(tài)模塊是無(wú)效的(即在創(chuàng)建store時(shí)聲明的模塊)。

5 含有vuex的項(xiàng)目的結(jié)構(gòu)

5.1 應(yīng)該遵循的規(guī)則

  1. 應(yīng)用層級(jí)的狀態(tài)都應(yīng)該集中在store中

  2. 提交 mutation 是更改狀態(tài)state的唯一方式程剥,并且這個(gè)過(guò)程是同步的劝枣。

  3. 異步的操作應(yīng)該都放在action里面

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子舔腾,更是在濱河造成了極大的恐慌溪胶,老刑警劉巖,帶你破解...
    沈念sama閱讀 218,755評(píng)論 6 507
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件稳诚,死亡現(xiàn)場(chǎng)離奇詭異哗脖,居然都是意外死亡,警方通過(guò)查閱死者的電腦和手機(jī)扳还,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,305評(píng)論 3 395
  • 文/潘曉璐 我一進(jìn)店門(mén)才避,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái),“玉大人氨距,你說(shuō)我怎么就攤上這事桑逝。” “怎么了俏让?”我有些...
    開(kāi)封第一講書(shū)人閱讀 165,138評(píng)論 0 355
  • 文/不壞的土叔 我叫張陵肢娘,是天一觀的道長(zhǎng)。 經(jīng)常有香客問(wèn)我舆驶,道長(zhǎng)橱健,這世上最難降的妖魔是什么? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 58,791評(píng)論 1 295
  • 正文 為了忘掉前任沙廉,我火速辦了婚禮拘荡,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘撬陵。我一直安慰自己珊皿,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,794評(píng)論 6 392
  • 文/花漫 我一把揭開(kāi)白布巨税。 她就那樣靜靜地躺著蟋定,像睡著了一般。 火紅的嫁衣襯著肌膚如雪草添。 梳的紋絲不亂的頭發(fā)上驶兜,一...
    開(kāi)封第一講書(shū)人閱讀 51,631評(píng)論 1 305
  • 那天,我揣著相機(jī)與錄音远寸,去河邊找鬼抄淑。 笑死,一個(gè)胖子當(dāng)著我的面吹牛驰后,可吹牛的內(nèi)容都是我干的肆资。 我是一名探鬼主播,決...
    沈念sama閱讀 40,362評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼灶芝,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼郑原!你這毒婦竟也來(lái)了唉韭?” 一聲冷哼從身側(cè)響起,我...
    開(kāi)封第一講書(shū)人閱讀 39,264評(píng)論 0 276
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤犯犁,失蹤者是張志新(化名)和其女友劉穎纽哥,沒(méi)想到半個(gè)月后,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體栖秕,經(jīng)...
    沈念sama閱讀 45,724評(píng)論 1 315
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡春塌,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,900評(píng)論 3 336
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了簇捍。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片只壳。...
    茶點(diǎn)故事閱讀 40,040評(píng)論 1 350
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖暑塑,靈堂內(nèi)的尸體忽然破棺而出吼句,到底是詐尸還是另有隱情,我是刑警寧澤事格,帶...
    沈念sama閱讀 35,742評(píng)論 5 346
  • 正文 年R本政府宣布惕艳,位于F島的核電站,受9級(jí)特大地震影響驹愚,放射性物質(zhì)發(fā)生泄漏远搪。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,364評(píng)論 3 330
  • 文/蒙蒙 一逢捺、第九天 我趴在偏房一處隱蔽的房頂上張望谁鳍。 院中可真熱鬧,春花似錦劫瞳、人聲如沸倘潜。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 31,944評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)涮因。三九已至,卻和暖如春伺绽,著一層夾襖步出監(jiān)牢的瞬間养泡,已是汗流浹背。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 33,060評(píng)論 1 270
  • 我被黑心中介騙來(lái)泰國(guó)打工憔恳, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留瓤荔,地道東北人净蚤。 一個(gè)月前我還...
    沈念sama閱讀 48,247評(píng)論 3 371
  • 正文 我出身青樓钥组,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國(guó)和親今瀑。 傳聞我的和親對(duì)象是個(gè)殘疾皇子程梦,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,979評(píng)論 2 355