十三、Vuex学习笔记
一、Vuex是做什么的?
官方解釋:Vuex 是一個專為 Vue.js 應(yīng)用程序開發(fā)的狀態(tài)管理模式。 它采用 集中式存儲管理
- 應(yīng)用的所有組件的狀態(tài),并以相應(yīng)的規(guī)則保證狀態(tài)以一種可預(yù)測的方式發(fā)生變化。
- Vuex 也集成到 Vue 的官方調(diào)試工具 devtools extension,提供了諸如零配置的 time-travel 調(diào)試、狀態(tài)快照導(dǎo)入導(dǎo)出等高級調(diào)試功能。
狀態(tài)管理到底是什么?
- 狀態(tài)管理模式、集中式存儲管理這些名詞聽起來就非常高大上,讓人捉摸不透。
其實,你可以簡單的將其看成把需要多個組件共享的變量全部存儲在一個對象里面。 - 然后,將這個對象放在頂層的Vue實例中,讓其他組件可以使用。
那么,多個組件是不是就可以共享這個對象中的所有變量屬性了呢?
- 等等,如果是這樣的話,為什么官方還要專門出一個插件Vuex呢?難道我們不能自己封裝一個對象來管理嗎?
- 當(dāng)然可以,只是我們要先想想VueJS帶給我們最大的便利是什么呢?沒錯,就是響應(yīng)式。
- 如果你自己封裝實現(xiàn)一個對象能不能保證它里面所有的屬性做到響應(yīng)式呢?當(dāng)然也可以,只是自己封裝可能稍微麻煩一些。
- 不用懷疑,Vuex就是為了提供這樣一個在多個組件間共享狀態(tài)的插件,用它就可以了。
二、管理什么狀態(tài)呢?
但是,有什么狀態(tài)時需要我們在多個組件間共享的呢?
- 如果你做過大型開放,你一定遇到過多個狀態(tài),在多個界面間的共享問題。
- 比如用戶的登錄狀態(tài)、用戶名稱、頭像、地理位置信息等等。
- 比如商品的收藏、購物車中的物品等等。
- 這些狀態(tài)信息,我們都可以放在統(tǒng)一的地方,對它進行保存和管理,而且它們還是響應(yīng)式的(待會兒我們就可以看到代碼了,莫著急)。
OK,從理論上理解了狀態(tài)管理之后,讓我們從實際的代碼再來看看狀態(tài)管理。
畢竟,Talk is cheap, Show me the code.(來自Linus)
我們先來看看但界面的狀態(tài)管理吧.
三、單界面的狀態(tài)管理
我們知道,要在單個組件中進行狀態(tài)管理是一件非常簡單的事情
什么意思呢?我們來看下面的圖片。
這圖片中的三種東西,怎么理解呢?
- State:不用多說,就是我們的狀態(tài)。(你姑且可以當(dāng)做就是data中的屬性)
- View:視圖層,可以針對State的變化,顯示不同的信息。(這個好理解吧?)
- Actions:這里的Actions主要是用戶的各種操作:點擊、輸入等等,會導(dǎo)致狀態(tài)的改變。
寫點代碼,加深理解:
看下右邊的代碼效果, 肯定會實現(xiàn)吧?
在這個案例中,我們有木有狀態(tài)需要管理呢?沒錯,就是個數(shù)counter。
- counter需要某種方式被記錄下來,也就是我們的State。
- counter目前的值需要被顯示在界面中,也就是我們的View部分。
- 界面發(fā)生某些操作時(我們這里是用戶的點擊,也可以是用戶的input),需要去更新狀態(tài),也就是我們的Actions
- 這不就是上面的流程圖了嗎?
四、多界面狀態(tài)管理
Vue已經(jīng)幫我們做好了單個界面的狀態(tài)管理,但是如果是多個界面呢?
- 多個視圖都依賴同一個狀態(tài)(一個狀態(tài)改了,多個界面需要進行更新)
- 不同界面的Actions都想修改同一個狀態(tài)(Home.vue需要修改,Profile.vue也需要修改這個狀態(tài))
也就是說對于某些狀態(tài)(狀態(tài)1/狀態(tài)2/狀態(tài)3)來說只屬于我們某一個視圖,但是也有一些狀態(tài)(狀態(tài)a/狀態(tài)b/狀態(tài)c)屬于多個試圖共同想要維護的
- 狀態(tài)1/狀態(tài)2/狀態(tài)3你放在自己的房間中,你自己管理自己用,沒問題。
- 但是狀態(tài)a/狀態(tài)b/狀態(tài)c我們希望交給一個大管家來統(tǒng)一幫助我們管理!!!
- 沒錯,Vuex就是為我們提供這個大管家的工具。
全局單例模式(大管家)
- 我們現(xiàn)在要做的就是將共享的狀態(tài)抽取出來,交給我們的大管家,統(tǒng)一進行管理。
- 之后,你們每個視圖,按照我規(guī)定好的規(guī)定,進行訪問和修改等操作。
- 這就是Vuex背后的基本思想。
Vuex狀態(tài)管理圖例:
四、Vuex的基本使用
我們還是實現(xiàn)一下之前簡單的案例
這里,我們先創(chuàng)建一個文件夾store,并且在其中創(chuàng)建一個index.js文件
在index.js文件中寫入如下代碼:
其次,我們讓所有的Vue組件都可以使用這個store對象
來到main.js文件,導(dǎo)入store對象,并且放在new Vue中
這樣,在其他Vue組件中,我們就可以通過this.$store的方式,獲取到這個store對象了
好的,這就是使用Vuex最簡單的方式了。
我們來對使用步驟,做一個簡單的小節(jié):
通過this.$store.state.屬性的方式來訪問狀態(tài)
通過this.$store.commit('mutation中方法')來修改狀態(tài)
注意事項:
- 我們通過提交mutation的方式,而非直接改變store.state.count。
- 這是因為Vuex可以更明確的追蹤狀態(tài)的變化,所以不要直接改變store.state.count的值。
五、Vuex核心概念
Vuex有幾個比較核心的概念:
我們對它進行一一介紹.
5.1 State單一狀態(tài)樹
Vuex提出使用單一狀態(tài)樹, 什么是單一狀態(tài)樹呢?
英文名稱是Single Source of Truth,也可以翻譯成單一數(shù)據(jù)源。
但是,它是什么呢?我們來看一個生活中的例子。
OK,我用一個生活中的例子做一個簡單的類比。
我們知道,在國內(nèi)我們有很多的信息需要被記錄,比如上學(xué)時的個人檔案,工作后的社保記錄,公積金記錄,結(jié)婚后的婚姻信息,以及其他相關(guān)的戶口、醫(yī)療、文憑、房產(chǎn)記錄等等(還有很多信息)。
這些信息被分散在很多地方進行管理,有一天你需要辦某個業(yè)務(wù)時(比如入戶某個城市),你會發(fā)現(xiàn)你需要到各個對應(yīng)的工作地點去打印、蓋章各種資料信息,最后到一個地方提交證明你的信息無誤。
這種保存信息的方案,不僅僅低效,而且不方便管理,以及日后的維護也是一個龐大的工作(需要大量的各個部門的人力來維護,當(dāng)然國家目前已經(jīng)在完善我們的這個系統(tǒng)了)。
這個和我們在應(yīng)用開發(fā)中比較類似:
如果你的狀態(tài)信息是保存到多個Store對象中的,那么之后的管理和維護等等都會變得特別困難。
所以Vuex也使用了單一狀態(tài)樹來管理應(yīng)用層級的全部狀態(tài)。
單一狀態(tài)樹能夠讓我們最直接的方式找到某個狀態(tài)的片段,而且在之后的維護和調(diào)試過程中,也可以非常方便的管理和維護。
5.2 Getters基本使用
有時候,我們需要從store中獲取一些state變異后的狀態(tài),比如下面的Store中:
獲取學(xué)生年齡大于20的個數(shù)。
如果我們已經(jīng)有了一個獲取所有年齡大于20歲學(xué)生列表的getters, 那么代碼可以這樣來寫:
我們可以在Store中定義getters:
getters默認是不能傳遞參數(shù)的, 如果希望傳遞參數(shù), 那么只能讓getters本身返回另一個函數(shù).
5.3 Mutation狀態(tài)更新
Vuex的store狀態(tài)的更新唯一方式:提交Mutation
Mutation主要包括兩部分:
- 字符串的事件類型(type)
- 一個回調(diào)函數(shù)(handler),該回調(diào)函數(shù)的第一個參數(shù)就是state。
mutation的定義方式:
通過mutation更新:
5.4 Mutation傳遞參數(shù)
在通過mutation更新數(shù)據(jù)的時候, 有可能我們希望攜帶一些額外的參數(shù)
- 參數(shù)被稱為是mutation的載荷(Payload)
Mutation中的代碼:
但是如果參數(shù)不是一個呢?
- 比如我們有很多參數(shù)需要傳遞.
- 這個時候, 我們通常會以對象的形式傳遞, 也就是payload是一個對象.
- 這個時候可以再從對象中取出相關(guān)的信息.
5.5 Mutation提交風(fēng)格
上面的通過commit進行提交是一種普通的方式
Vue還提供了另外一種風(fēng)格, 它是一個包含type屬性的對象
Mutation中的處理方式是將整個commit的對象作為payload使用, 所以代碼沒有改變, 依然如下:
5.6 Mutation響應(yīng)規(guī)則
Vuex的store中的state是響應(yīng)式的, 當(dāng)state中的數(shù)據(jù)發(fā)生改變時, Vue組件會自動更新.
這就要求我們必須遵守一些Vuex對應(yīng)的規(guī)則:
方式一: 使用Vue.set(obj, ‘newProp’, 123)
方式二: 用心對象給舊對象重新賦值
5.7 Mutation常量類型 – 概念
我們來考慮下面的問題:
- 在mutation中, 我們定義了很多事件類型(也就是其中的方法名稱).
- 當(dāng)我們的項目增大時, Vuex管理的狀態(tài)越來越多, 需要更新狀態(tài)的情況越來越多, 那么意味著Mutation中的方法越來越多.
- 方法過多, 使用者需要花費大量的經(jīng)歷去記住這些方法, 甚至是多個文件間來回切換, 查看方法名稱, 甚至如果不是復(fù)制的時候, 可能還會出現(xiàn)寫錯的情況.
如何避免上述的問題呢?
- 在各種Flux實現(xiàn)中, 一種很常見的方案就是使用常量替代Mutation事件的類型.
- 我們可以將這些常量放在一個單獨的文件中, 方便管理以及讓整個app所有的事件類型一目了然.
具體怎么做呢?
-
我們可以創(chuàng)建一個文件: mutation-types.js, 并且在其中定義我們的常量.
-
定義常量時, 我們可以使用ES2015中的風(fēng)格, 使用一個常量來作為函數(shù)的名稱.
5.8 Mutation同步函數(shù)
通常情況下, Vuex要求我們Mutation中的方法必須是同步方法.
主要的原因是當(dāng)我們使用devtools時, 可以devtools可以幫助我們捕捉mutation的快照.
但是如果是異步操作, 那么devtools將不能很好的追蹤這個操作什么時候會被完成.
比如我們之前的代碼, 當(dāng)執(zhí)行更新時, devtools中會有如下信息: 圖1
但是, 如果Vuex中的代碼, 我們使用了異步函數(shù): 圖2
你會發(fā)現(xiàn)state中的info數(shù)據(jù)一直沒有被改變, 因為他無法追蹤到.
So, 通常情況下, 不要再mutation中進行異步的操作
5.9 Action的基本定義
我們強調(diào), 不要再Mutation中進行異步操作. 但是某些情況, 我們確實希望在Vuex中進行一些異步操作, 比如網(wǎng)絡(luò)請求,
必然是異步的. 這個時候怎么處理呢?
Action類似于Mutation, 但是是用來代替Mutation進行異步操作的.
Action的基本使用代碼如下:
context是什么?
- context是和store對象具有相同方法和屬性的對象.
- 也就是說, 我們可以通過context去進行commit相關(guān)的操作, 也可以獲取context.state等.
- 但是注意, 這里它們并不是同一個對象, 為什么呢? 我們后面學(xué)習(xí)Modules的時候, 再具體說.
這樣的代碼是否多此一舉呢?
我們定義了actions, 然后又在actions中去進行commit, 這不是脫褲放屁嗎?
事實上并不是這樣, 如果在Vuex中有異步操作, 那么我們就可以在actions中完成了.
5.10 Action的分發(fā)
在Vue組件中, 如果我們調(diào)用action中的方法, 那么就需要使用dispatch:
同樣的, 也是支持傳遞payload:
5.11 Action返回的Promise
前面我們學(xué)習(xí)ES6語法的時候說過, Promise經(jīng)常用于異步操作.
在Action中, 我們可以將異步操作放在一個Promise中, 并且在成功或者失敗后, 調(diào)用對應(yīng)的resolve或reject.
OK, 我們來看下面的代碼:
5.12 認識Module
Module是模塊的意思, 為什么在Vuex中我們要使用模塊呢?
- Vue使用單一狀態(tài)樹,那么也意味著很多狀態(tài)都會交給Vuex來管理.
- 當(dāng)應(yīng)用變得非常復(fù)雜時,store對象就有可能變得相當(dāng)臃腫.
- 為了解決這個問題, Vuex允許我們將store分割成模塊(Module), 而每個模塊擁有自己的state、mutations、actions、getters等
我們按照什么樣的方式來組織模塊呢?
我們來看下邊的代碼:
上面的代碼中, 我們已經(jīng)有了整體的組織結(jié)構(gòu), 下面我們來看看具體的局部模塊中的代碼如何書寫.
我們在moduleA中添加state、mutations、getters
mutation和getters接收的第一個參數(shù)是局部狀態(tài)對象
5.13 Module中 Actions的寫法
actions的寫法呢? 接收一個context參數(shù)對象
局部狀態(tài)通過 context.state 暴露出來,根節(jié)點狀態(tài)則為 context.rootState
如果getters中也需要使用全局的狀態(tài), 可以接受更多的參數(shù)
六、項目結(jié)構(gòu)
當(dāng)我們的Vuex幫助我們管理過多的內(nèi)容時, 好的項目結(jié)構(gòu)可以讓我們的代碼更加清晰.
總結(jié)
以上是生活随笔為你收集整理的十三、Vuex学习笔记的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: Nodejs ejs模板引擎
- 下一篇: Vue项目中使用百度地图API