?
This document uses PHP Chinese website manual Release
Vuex 使用 單一狀態(tài)樹 - 是的,用一個(gè)對(duì)象就包含了全部的應(yīng)用層級(jí)狀態(tài),然后作為一個(gè)『唯一數(shù)據(jù)源(SSOT)』而存在。這也意味著,每一個(gè)應(yīng)用將只有一個(gè) store 實(shí)例。單一狀態(tài)樹讓我們能夠直接地定位任一特定的狀態(tài)片段,在調(diào)試的過程中也能輕易地取得整個(gè)當(dāng)前應(yīng)用狀態(tài)的快照。
單狀態(tài)樹和模塊化并不沖突 - 在后面的章節(jié)里我們會(huì)討論如何將狀態(tài)(state)和狀態(tài)變更事件(mutation)分布到各個(gè)子模塊中。
那么我們?nèi)绾卧?Vue 組件中展示狀態(tài)呢?由于 Vuex 的狀態(tài)存儲(chǔ)是響應(yīng)式的,從 store 實(shí)例中讀取狀態(tài)最簡(jiǎn)單的方法,就是在計(jì)算屬性的函數(shù)中直接返回某個(gè) store 的狀態(tài):
// 創(chuàng)建一個(gè)計(jì)數(shù)器組件 const Counter = { template: `<div>{{ count }}</div>`, computed: { count () { return store.state.count } } }
當(dāng) store.state.count
發(fā)生變化,將會(huì)引發(fā)重新對(duì)計(jì)算屬性取值,并且相關(guān)聯(lián)的 DOM 將觸發(fā)更新。
然而,這種模式導(dǎo)致組件依賴于全局狀態(tài)單例。當(dāng)使用模塊系統(tǒng)時(shí),還需要在每個(gè)組件都去引入 store,才能使每個(gè)組件都能使用 store 的狀態(tài),同時(shí)測(cè)試組件時(shí)也需要模擬出 store。
Vuex 提供一個(gè)機(jī)制,設(shè)置 store
選項(xiàng)(啟用Vue.use(Vuex)
)將 store 從根組件『注入』到每一個(gè)子組件中:
const app = new Vue({ el: '#app', // 使用 "store" 選項(xiàng)后,可以注冊(cè) store 對(duì)象。將會(huì)把 store 實(shí)例注入到所有子組件。 store, components: { Counter }, template: ` <div class="app"> <counter></counter> </div> ` })
通過在根實(shí)例中注冊(cè) store
選項(xiàng),該 store 實(shí)例會(huì)被注入到根組件下的所有子組件中,并且子組件可以通過 this.$store
來訪問。讓我們一起調(diào)整剛才 計(jì)數(shù)器
的實(shí)現(xiàn):
const Counter = { template: `<div>{{ count }}</div>`, computed: { count () { return this.$store.state.count } } }
mapState
工具
當(dāng)一個(gè)組件需要引用 store 的多個(gè) state 屬性或 getter 函數(shù)時(shí),聲明列舉出所有計(jì)算屬性會(huì)變得重復(fù)且繁瑣。為了解決這個(gè)問題,我們可以使用 mapState
工具,它為我們生成 computed 所需的很多個(gè) getter 函數(shù),幫助我們節(jié)省一些鍵盤按鍵(^_^):
// vuex 提供了獨(dú)立的構(gòu)建工具函數(shù) Vuex.mapState import { mapState } from 'vuex' export default { // ... computed: mapState({ // 箭頭函數(shù)可以讓代碼非常簡(jiǎn)潔 count: state => state.count, // 傳入字符串 'count' 等同于 `state => state.count` countAlias: 'count', // 想訪問局部狀態(tài),就必須借助于一個(gè)普通函數(shù),函數(shù)中使用 `this` 獲取局部狀態(tài) countPlusLocalState (state) { return state.count + this.localCount } }) }
當(dāng)計(jì)算屬性名稱和狀態(tài)子樹名稱對(duì)應(yīng)相同時(shí),我們可以向 mapState
工具函數(shù)傳入一個(gè)字符串?dāng)?shù)組。
computed: mapState([ // 映射 state.count 到 store.this.count 'count' ])
注意,mapState
返回一個(gè)對(duì)象。我們?nèi)绾问褂?mapState 合并其他局部的計(jì)算屬性呢?通常地,為了將多個(gè)對(duì)象合并為一個(gè)對(duì)象,再把這個(gè)合并好的最終對(duì)象傳入到 computed
屬性去,我們不得不使用一個(gè)工具函數(shù)來實(shí)現(xiàn)。然而有了對(duì)象擴(kuò)展運(yùn)算符(ECMAScript 提案 stage-3),我們可以大大簡(jiǎn)化語法:
computed: { localComputed () { /* ... */ }, // 使用對(duì)象擴(kuò)展運(yùn)算符,將 mapState 返回的對(duì)象和外層其他計(jì)算屬性混合起來 ...mapState({ // ... }) }
使用 Vuex 并不意味你應(yīng)該把 所有 狀態(tài)都放在 Vuex 中去管理。盡管把更多的狀態(tài)放到 Vuex 管理,會(huì)讓狀態(tài)變化變得更加清晰和可調(diào)試,但有時(shí)也能使代碼變得冗余和不直觀。如果某部分狀態(tài)嚴(yán)格屬于一個(gè)單獨(dú)的組件,那就只把這部分狀態(tài)作為局部狀態(tài)就好了。你應(yīng)該權(quán)衡利弊,做適合您的 App 開發(fā)需求的決策。