參考資料:
https://juejin.im/post/59097cd7a22b9d0065fb61d2
Vuex是一個(gè)專門(mén)為Vue.js應(yīng)用程序開(kāi)發(fā)的狀態(tài)管理模式。它采用集中式存儲(chǔ)管理應(yīng)用的所有組件的狀態(tài),并以相應(yīng)的規(guī)則保證狀態(tài)以一種可預(yù)測(cè)的方式發(fā)生變化婶芭。
什么是“狀態(tài)管理模式”牢裳?
一個(gè)狀態(tài)自管理應(yīng)用包含以下幾個(gè)部分:
state:驅(qū)動(dòng)應(yīng)用的數(shù)據(jù)源
view:以聲明方式將state映射到視圖
action:響應(yīng)在view上的用戶輸入導(dǎo)致的狀態(tài)變化
當(dāng)我們的應(yīng)用遇到多個(gè)組件共享狀態(tài)時(shí),例如:
1. 多個(gè)視圖依賴于同一狀態(tài)隆檀。傳參的方法對(duì)于多層嵌套的組件會(huì)非常繁瑣摇天,并且無(wú)法在兄弟組件中傳遞狀態(tài)。
2. 來(lái)自不同視圖的行為需要變更同一狀態(tài)恐仑。采用父子組件或者通過(guò)事件來(lái)變更和同步狀態(tài)的多份拷貝泉坐。
上面的方法都非常脆弱,會(huì)導(dǎo)致代碼難以維護(hù)裳仆,于是想到把組件的共享狀態(tài)抽取出來(lái)腕让,以一個(gè)全局單一實(shí)例的模式來(lái)管理。這樣應(yīng)用的組件就構(gòu)成了一個(gè)巨大的“視圖”樹(shù)歧斟,不管組件位于樹(shù)的那個(gè)位置纯丸,都可以獲取狀態(tài)和觸發(fā)行為,這就是Vuex的基本思想静袖。Vuex是專門(mén)為Vue.js設(shè)計(jì)的狀態(tài)管理庫(kù)觉鼻,以利用Vue.js的細(xì)顆粒度數(shù)據(jù)響應(yīng)機(jī)制來(lái)進(jìn)行高效的狀態(tài)更新。
每一個(gè)Vuex應(yīng)用的核心就是store倉(cāng)庫(kù)队橙,store就像一個(gè)容器坠陈,它包含著應(yīng)用中大部分的狀態(tài)state。但是Vuex和單純的全局對(duì)象又一下不同:
1. Vuex的狀態(tài)存儲(chǔ)是響應(yīng)式的喘帚。當(dāng)vue組件從store中讀取狀態(tài)的時(shí)候畅姊,若store中的狀態(tài)發(fā)生變化,那么相應(yīng)的組件也會(huì)高效跟新吹由。
2. 不能直接得改變store中的狀態(tài)若未,只有顯示地提交commit mutation才能改變store中的狀態(tài)值。這樣就可以跟蹤每一個(gè)狀態(tài)的變化倾鲫。
Vuex使用“單一狀態(tài)樹(shù)”粗合,用一個(gè)對(duì)象就包含了全部的應(yīng)用層級(jí)狀態(tài)。每一個(gè)應(yīng)用只包含一個(gè)store實(shí)例乌昔,是整個(gè)應(yīng)用的“唯一數(shù)據(jù)源”隙疚。單一狀態(tài)樹(shù)讓我們能夠直接地定位任一特定的狀態(tài)片段,在調(diào)試的過(guò)程中也能輕易地取得整個(gè)當(dāng)前應(yīng)用狀態(tài)的快照磕道。
Vuex通過(guò)store選項(xiàng)供屉,提供了一種機(jī)制將狀態(tài)從根組件注入到每個(gè)子組件中。在根實(shí)例中注冊(cè)Store選項(xiàng),該store實(shí)例會(huì)注入到根組件下的所有子組件中伶丐,且子組件能通過(guò)this.$store訪問(wèn)到悼做。
當(dāng)一個(gè)組件需要獲取多個(gè)狀態(tài)的時(shí)候,將這些狀態(tài)都聲明為計(jì)算屬性會(huì)有些重復(fù)和冗余哗魂,這時(shí)可以使用mapState輔助函數(shù)幫助我們生產(chǎn)計(jì)算屬性肛走,將html組件中需要的狀態(tài)和store中的狀態(tài)對(duì)應(yīng)起來(lái)。
當(dāng)映射的計(jì)算屬性的名稱與state的子節(jié)點(diǎn)名稱相同時(shí)录别,可以給mapState傳一個(gè)字符串?dāng)?shù)組:
Vuex允許在store中定義getter朽色,可以認(rèn)為是store的計(jì)算屬性。getter的返回值會(huì)根據(jù)它的依賴被緩存起來(lái)组题,只有當(dāng)它的依賴值發(fā)生改變才會(huì)被重新計(jì)算葫男。這樣getter中定義的函數(shù)就可以被多個(gè)組件調(diào)用。
Getter會(huì)暴露為store.getters對(duì)象往踢,可以以屬性的形式訪問(wèn)腾誉,也可以接受其他getter作為第二個(gè)參數(shù)。還可以通過(guò)讓getter返回一個(gè)函數(shù)峻呕,來(lái)實(shí)現(xiàn)給getter傳參數(shù)利职,在種方法在對(duì)數(shù)組進(jìn)行查詢時(shí)非常有用(getter 在通過(guò)方法訪問(wèn)時(shí),每次都會(huì)去進(jìn)行調(diào)用瘦癌,而不會(huì)緩存結(jié)果猪贪。):
mapGetters輔助函數(shù)也是將store中的getter映射到局部計(jì)算屬性:
更改Vuex的store中的狀態(tài)的唯一方法是提交mutation。Vuex中的mutation類似于事件:每個(gè)mutation都有一個(gè)字符串的事件類型(type)和一個(gè)回調(diào)函數(shù)(handler)讯私。利用回調(diào)函數(shù)更改狀態(tài)热押,state作為第一個(gè)參數(shù)。mutation handler是不能直接調(diào)用的斤寇,需要以相應(yīng)的type調(diào)用store.commit方法注冊(cè)事件:“當(dāng)觸發(fā)一個(gè)類型為increment的mutation時(shí)桶癣,調(diào)用這個(gè)回調(diào)函數(shù)”。
mutation的載荷payload是指向store.commit傳入的額外參數(shù)牙寞,載荷應(yīng)該是一個(gè)對(duì)象。提交mutation的另一種方式是直接使用包含type屬性的對(duì)象莫秆。當(dāng)使用對(duì)象風(fēng)格的提交方式间雀,整個(gè)對(duì)象都作為載荷傳給mutation函數(shù),因此回調(diào)函數(shù)handler就可以保持不變:
Vuex的store中的狀態(tài)是響應(yīng)式的镊屎,那么當(dāng)我們變更狀態(tài)時(shí)惹挟,監(jiān)視狀態(tài)的vue組件也會(huì)自動(dòng)更新。mutation需要遵守vue的響應(yīng)規(guī)則:
1. 最好提前在你的store中初始化好需要的屬性缝驳。
2. 當(dāng)需要在對(duì)象上添加新屬性時(shí)连锯,有2種方式:
? ? a.使用 Vue.set(obj, 'newProp', 123)
? ? b. 以新對(duì)象替換老對(duì)象:state.obj = {...state.obj, newProp:123}
添加一個(gè)按鈕归苍,點(diǎn)擊一次加1
使用mapMutations輔助函數(shù)將組件的methods中的方法映射到store.commit調(diào)用:
mutation 都是同步事務(wù)。mutation必須是同步函數(shù)运怖。如果我們正在debug一個(gè)app并且觀察devtool中的mutation日志霜医。每一條mutation被記錄,devtools都需要捕捉到前一狀態(tài)和后一狀態(tài)的快照驳规。然而,mutation 中的異步函數(shù)中的回調(diào)讓這不可能完成:因?yàn)楫?dāng) mutation 觸發(fā)的時(shí)候署海,回調(diào)函數(shù)還沒(méi)有被調(diào)用吗购,devtools 不知道什么時(shí)候回調(diào)函數(shù)實(shí)際上被調(diào)用——實(shí)質(zhì)上任何在回調(diào)函數(shù)中進(jìn)行的狀態(tài)的改變都是不可追蹤的。
Action類似于mutation砸狞。不同處在于:
1. action提交的是mutation捻勉,而不是直接變更狀態(tài)
2. action可以包含任意異步操作
Action通過(guò)store.dispatch方法觸發(fā):
Actions同樣支持載荷方式和對(duì)象方式進(jìn)行分發(fā):
在組件中使用this.$store.dispath('actionName')來(lái)分發(fā)action,或者使用mapAction輔助函數(shù)將組件中的methods映射為store.dispatch調(diào)用:
Action組合使用:
此處需要先學(xué)習(xí)JS的異步函數(shù) :
http://www.reibang.com/writer#/notebooks/37007324/notes/47700732
store.dispatch可以處理被觸發(fā)的action的處理函數(shù)返回的Promise刀森,并且store.dispatch仍舊返回Promise踱启。
當(dāng)app的所有狀態(tài)都集中到一個(gè)store對(duì)象中,store會(huì)變的相當(dāng)臃腫研底。vuex允許我們將store分割成模塊module埠偿。每個(gè)模塊擁有自己的state,mutation榜晦,action冠蒋,getter:
Vue項(xiàng)目結(jié)構(gòu)通用規(guī)則:
1. 應(yīng)用層級(jí)的狀態(tài)應(yīng)該集中到單個(gè)store對(duì)象中。
2.提交mutation是更改狀態(tài)的唯一方法乾胶,這個(gè)過(guò)程是同步的抖剿。
3.異步邏輯都應(yīng)該封裝到action里面。
4.如果store文件太大识窿,可以將action斩郎,mutation和getter分割到單獨(dú)的文件中。
插件plugin
Vuex的store接受plugins選項(xiàng)喻频,這個(gè)選項(xiàng)暴露出每次mutation的鉤子缩宜。Vuex插件就是一個(gè)函數(shù),它接受store作為唯一參數(shù):
插件中需要提交mutation來(lái)改變store的狀態(tài)值半抱,所以插件可以用來(lái)同步數(shù)據(jù)源到store脓恕。
嚴(yán)格模式
在創(chuàng)建store的時(shí)候傳入strict:true就開(kāi)啟嚴(yán)了格模式,無(wú)論何時(shí)發(fā)生了不是由mutation函數(shù)引起的狀態(tài)變更窿侈,就會(huì)拋出錯(cuò)誤炼幔。不要在發(fā)布環(huán)境下啟用嚴(yán)格模式!嚴(yán)格模式會(huì)深度監(jiān)測(cè)狀態(tài)樹(shù)來(lái)檢測(cè)不合規(guī)的狀態(tài)變更——請(qǐng)確保在發(fā)布環(huán)境下關(guān)閉嚴(yán)格模式史简,以避免性能損失乃秀。
使用vuex的思維處理表單:
給?<input>?中綁定 value肛著,然后偵聽(tīng)?input?或者?change?事件,在事件回調(diào)中調(diào)用 action:
熱重載:
使用 webpack 的?Hot Module Replacement API跺讯,Vuex 支持在開(kāi)發(fā)過(guò)程中熱重載 mutation枢贿、module、action 和 getter刀脏。對(duì)于 mutation 和模塊局荚,你需要使用?store.hotUpdate()?方法: