Vuex入門學習手冊
Vuex介紹。
基本介紹
Vuex 是一個專為 Vue.js 應用程式開發的狀態管理模式。它採用集中式儲存管理應用的所有元件的狀態,並以相應的規則保證狀態以一種可預測的方式發生變化。Vuex的主要作用是將狀態(在data中的屬性需要共享給其他vue元件使用的部分)單獨拎出來,應用統一的方式進行處理,保證各元件間的狀態同步(以及同一組件再次顯示時的狀態保持)。
通俗來說:
Vuex 就是前端為了方便資料的操作而建立的一個”前端資料庫 ”
不同的模組元件能通過統一的方法獲取,修改資料內容
store>倉庫
state>源資料
mutation>Mutations 就是我們把資料存入資料庫的 API,用來修改state 的唯一方法
getter> getters 是我們從資料庫裡取資料的 API,是一個”純函式“,不會對原資料造成影響的函式
它規定了一些需要遵守的規則:
應用層級的狀態應該集中到單個 store 物件中。
提交 mutation 是更改狀態的唯一方法,並且這個過程是同步的。
非同步邏輯都應該封裝到 action 裡面。
應用場景
Vuex採用和Redux類似的單向資料流的方式來管理資料。使用者介面負責觸發動作(Action)進而改變對應狀態(State),從而反映到檢視(View)上。這個狀態自管理應用包含以下幾個部分:
state,驅動應用的資料來源;
view,以宣告方式將 state 對映到檢視;
actions,響應在 view 上的使用者輸入導致的狀態變化。
以下是一個表示“單向資料流”理念的極簡示意:
當搭建中,大型元件化的SPA應用,必定會牽扯到多個元件間的通訊,單向資料流的簡潔性很容易被破壞:
多個檢視依賴於同一狀態。
來自不同檢視的行為需要變更同一狀態。
為了解決以上問題,應用Vuex,把元件的共享狀態抽取出來,以一個全域性單例模式管理。在這種模式下,我們的元件樹構成了一個巨大的“檢視”,不管在樹的哪個位置,任何元件都能獲取狀態或者觸發行為!
vuex安裝及配置
安裝
利用npm包管理工具,進行安裝 vuex。在控制命令列中輸入下邊的命令就可以了
npm install vuex –save
注意:這裡一定要加上 –save,因為你這個包我們在生產環境(devDependencies)中是要使用的。
配置
新建一個store資料夾,並在資料夾下新建index.js檔案,檔案中引入我們的vue和vuex,引入之後用Vue.use進行引用。
在main.js 中引入新建的vuex檔案,然後 , 在例項化 Vue物件時加入 store 物件 :
import storeConfig from './vuex/store'
new Vue({
el: '#app',
router,
store,//使用store
template: '<App/>',
components: { App }
})
核心概念
state
State負責儲存整個應用的狀態資料(state就是根據你專案的需求,自己定義一個數據結構,是我們單頁應用程式中的共享值),一般需要在使用的時候在跟節點注入Store(相當於倉庫)物件(store中至少要注入兩項,state 和 mutation)。
在元件使用的過程中,如果想要獲取對應的狀態你就可以直接使用this.$store.state獲取,當然,也可以將
狀態物件賦值給內部物件,也就是把index.js中的值,賦值給我們模板裡data中的值。有三種賦值方式
- 通過computed的計算屬性直接賦值
computed:{count(){return this.$store.state.count;}}
- 通過mapState的物件來賦值
import {mapState} from 'vuex'; computed:mapState({count:state=>state.count })
理解為傳入state物件,使用ES6的箭頭函式來給count賦值,修改state.count屬性。- 通過mapState的陣列來賦值
computed:mapState(["count"])
getters
getters從表面是獲得的意思(可以認為是 store 的計算屬性),可以把他看作在獲取資料之前進行的一種再編輯,相當於對某些狀態做二次處理( 對資料的一個過濾和加工 )。getters 是一個純函式,接收引數 state,返回值會根據它的依賴被快取起來,且只有當它的依賴值發生了改變才會被重新計算。
getters基本用法:
比如我們現在要對index.js檔案中的count進行一個計算屬性的操作,就是在它輸出前,給它加上100.我們首先要在index.js裡用const宣告我們的getters屬性。
寫好了gettters之後,我們還需要在Vuex.Store()裡引入,在index.js裡的配置算是完成了,我們需要到模板頁對computed進行配置。在vue 的構造器裡邊只能有一個computed屬性,如果你寫多個,只有最後一個computed屬性可用,所以要對上節課寫的computed屬性進行一個改造。改造時我們使用ES6中的展開運算子”…”。
或者用mapGetters簡化模板寫法,將 store 中的 getter 對映到區域性計算屬性,如下:
mutations
Mutations的中文意思是“變化”,利用它可以更改狀態(是操作state的唯一方法,即只有mutations方法能夠改變state狀態值),Vuex 中的 mutation 非常類似於事件:每個 mutation 都有一個字串的 事件型別 (type) 和 一個 回撥函式 (handler)。這個回撥函式就是我們實際進行狀態更改的地方,並且它會接受 state 作為第一個引數:
Mutation 需遵守 Vue 的響應規則:
- 最好提前在你的 store 中初始化好所有所需屬性。
- 當需要在物件上新增新屬性時,你應該
使用 Vue.set(obj, ‘newProp’, 123), 或者以新物件替換老物件。
例如,利用 stage-3 的物件展開運算子我們可以這樣寫:
state.obj = { …state.obj, newProp: 123 }
你可以在元件中使用 this.$store.commit(‘xxx’) 提交 mutation,或者使用 mapMutations 輔助函式將元件中的 methods 對映為 store.commit 呼叫(需要在根節點注入 store,如上圖)。
store.commit(mutationName)是用來觸發一個mutation的方法。需要記住的是,定義的mutation必須是同步函式,否則devtool中的資料將可能出現問題,使狀態改變變得難以跟蹤。
Action
Actions也可以用於改變狀態,不過是通過觸發mutation實現的,重要的是可以包含非同步操作。其輔助函式是mapActions與mapMutations類似,也是繫結在元件的methods上的。如果選擇直接觸發的話,使用this.$store.dispatch(actionName)方法。關於action和mutations的區別有以下幾點:
Action 提交的是 mutation,而不是直接變更狀態。
Action 可以包含任意非同步操作。
Action 還是得通過 mutation 方法來修改state
同樣是之前的increment方法,我們分別用同步和非同步的action來驗證上面所說的與mutations的不同之處:
actions: { //定義Actions
increment (context) {
context.commit('increment') //context上下文物件,這裡你可以理解稱store本身
},
incrementAsync (commit) {// 延時1秒
setTimeout(() => {
context.commit('increment') //{commit}:直接把commit物件傳遞過來,可以讓方法體邏輯和程式碼更清晰明瞭
}, 1000)
}
}
context是與 store 例項具有相同方法和屬性的物件。可以通過context.state和context.getters來獲取 state 和 getters。不同於mutations使用commit方法,actions使用dispatch方法,this.$store.dispatch(‘incrementAsync’)。
在元件中分發 Action:
import { mapActions } from 'vuex'
export default {
methods: {
...mapActions([
'increment', // 將 `this.increment()` 對映為 `this.$store.dispatch('increment')`
// `mapActions` 也支援載荷:
'incrementBy' // 將 `this.incrementBy(amount)` 對映為 `this.$store.dispatch('incrementBy', amount)`
]),
...mapActions({
add: 'increment' // 將 `this.add()` 對映為 `this.$store.dispatch('increment')`
})
}
}
module
module:狀態管理器的模組組操作。使用單一狀態樹,導致應用的所有狀態集中到一個很大的物件。但是,當應用變得很大時,store 物件會變得臃腫不堪。這時候我們就需要把我們狀態的各種操作進行一個分組,分組後再進行按組編寫。
Vuex 允許我們將 store 分割到模組(module)。每個模組擁有自己的 state、mutation、action、getters、甚至是巢狀子模組——從上至下進行類似的分割。
宣告模組組:在vuex/index.js中宣告模組組,我們還是用我們的const常量的方法宣告模組組。宣告好後,我們需要修改原來 Vuex.Stroe裡的值:程式碼如下
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 的狀態
store.state.b // -> moduleB 的狀態
在模板中使用:現在我們要在模板中使用count狀態,要用插值的形式寫入。如果想用簡單的方法引入,還是要在我們的計算屬性中rutrun我們的狀態。
<h3>{{$store.state.a.count}}</h3> //插值寫入
computed:{ //計算屬性中rutrun我們的狀態
count(){
return this.$store.state.a.count;
}
}
Plugins
外掛就是一個鉤子函式,在初始化store的時候引入即可。比較常用的是內建的logger外掛,用於作為除錯使用。
在外掛中不允許直接修改狀態——類似於元件,只能通過提交 mutation 來觸發變化。
通過提交 mutation,外掛可以用來同步資料來源到 store。
const myPlugin = store => {
// 當 store 初始化後呼叫
store.subscribe((mutation, state) => {
// 每次 mutation 之後呼叫
// mutation 的格式為 { type, payload }
})
}
//然後像這樣使用:
const store = new Vuex.Store({
// ...
plugins: [myPlugin]
})