作者: Yeaseon
Blog:yeaseonzhang.github.io
原文連結
本文基本上是官方教程的盜版,用通俗易懂的文字講解Vuex,也對原文內容有刪減。
如果你對以上宣告不介意,那麼就可以繼續看本文,希望對你有所幫助。
學習一個新技術,必須要清楚兩個W,"What && Why"。
"XX 是什麼?","為什麼要使用 XX ,或者說 XX 有什麼好處",最後才是"XX 怎麼使用"。
Vuex是什麼?
Vuex 類似 Redux 的狀態管理器,用來管理Vue的所有元件狀態。
為什麼使用Vuex?
當你打算開發大型單頁應用(SPA),會出現多個檢視元件依賴同一個狀態,來自不同檢視的行為需要變更同一個狀態。
遇到以上情況時候,你就應該考慮使用Vuex了,它能把元件的共享狀態抽取出來,當做一個全域性單例模式進行管理。這樣不管你在何處改變狀態,都會通知使用該狀態的元件做出相應修改。
下面講解如何使用Vuex。
最簡單的Vuex示例
本文就不涉及如何安裝Vuex,直接通過程式碼講解。
import Vue from 'vue';
import Vuex form 'vuex';
Vue.use(Vuex);
const store = new Vuex.Store({
state: {
count: 0
},
mutations: {
increment (state) {
state.count++
}
}
})複製程式碼
以上就是一個最簡單的Vuex,每一個Vuex應用就是一個store,在store中包含元件中的共享狀態state
和改變狀態的方法(暫且稱作方法)mutations
。
需要注意的是隻能通過mutations
改變store的state
的狀態,不能通過store.state.count = 5;
直接更改(其實可以更改,不建議這麼做,不通過mutations
改變state
,狀態不會被同步)。
使用store.commit
方法觸發mutations
改變state
:
store.commit('increment');
console.log(store.state.count) // 1複製程式碼
一個簡簡單單的Vuex應用就實現了。
在Vue元件使用Vuex
如果希望Vuex狀態更新,相應的Vue元件也得到更新,最簡單的方法就是在Vue的computed
(計算屬性)獲取state
// Counter 元件
const Counter = {
template: `<div>{{ count }}</div>`,
computed: {
count () {
return store.state.count;
}
}
}複製程式碼
上面的例子是直接操作全域性狀態store.state.count
,那麼每個使用該Vuex的元件都要引入。為了解決這個,Vuex通過store
選項,提供了一種機制將狀態從根元件注入到每一個子元件中。
// 根元件
import Vue from 'vue';
import Vuex form 'vuex';
Vue.use(Vuex);
const app = new Vue({
el: '#app',
store,
components: {
Counter
},
template: `
<div class="app">
<counter></counter>
</div>
`
})複製程式碼
通過這種注入機制,就能在子元件Counter
通過this.$store
訪問:
// Counter 元件
const Counter = {
template: `<div>{{ count }}</div>`,
computed: {
count () {
return this.$store.state.count
}
}
}複製程式碼
mapState函式
computed: {
count () {
return this.$store.state.count
}
}複製程式碼
這樣通過count
計算屬性獲取同名state.count
屬性,是不是顯得太重複了,我們可以使用mapState
函式簡化這個過程。
import { mapState } from 'vuex';
export default {
computed: mapState ({
count: state => state.count,
countAlias: 'count', // 別名 `count` 等價於 state => state.count
})
}複製程式碼
還有更簡單的使用方法:
computed: mapState([
// 對映 this.count 為 store.state.count
'count'
])複製程式碼
Getters物件
如果我們需要對state
物件進行做處理計算,如下:
computed: {
doneTodosCount () {
return this.$store.state.todos.filter(todo => todo.done).length
}
}複製程式碼
如果多個元件都要進行這樣的處理,那麼就要在多個元件中複製該函式。這樣是很沒有效率的事情,當這個處理過程更改了,還有在多個元件中進行同樣的更改,這就更加不易於維護。
Vuex中getters
物件,可以方便我們在store
中做集中的處理。Getters接受state
作為第一個引數:
const store = new Vuex.Store({
state: {
todos: [
{ id: 1, text: '...', done: true },
{ id: 2, text: '...', done: false }
]
},
getters: {
doneTodos: state => {
return state.todos.filter(todo => todo.done)
}
}
})複製程式碼
在Vue中通過store.getters
物件呼叫。
computed: {
doneTodos () {
return this.$store.getters.doneTodos
}
}複製程式碼
Getter也可以接受其他getters作為第二個引數:
getters: {
doneTodos: state => {
return state.todos.filter(todo => todo.done)
},
doneTodosCount: (state, getters) => {
return getters.doneTodos.length
}
}複製程式碼
mapGetters輔助函式
與mapState
類似,都能達到簡化程式碼的效果。mapGetters
輔助函式僅僅是將store中的getters對映到區域性計算屬性:
import { mapGetters } from 'vuex'
export default {
// ...
computed: {
// 使用物件展開運算子將 getters 混入 computed 物件中
...mapGetters([
'doneTodosCount',
'anotherGetter',
// ...
])
}
}複製程式碼
上面也可以寫作:
computed: mapGetters([
'doneTodosCount',
'anotherGetter',
// ...
])複製程式碼
所以在Vue的computed
計算屬性中會存在兩種輔助函式:
import { mapState, mapGetters } form 'vuex';
export default {
// ...
computed: {
mapState({ ... }),
mapGetter({ ... })
}
}複製程式碼
Mutations
之前也說過了,更改Vuex的store中的狀態的唯一方法就是mutations
。
每一個mutation
都有一個事件型別type
和一個回撥函式handler
。
const store = new Vuex.Store({
state: {
count: 1
},
mutations: {
increment (state) {
// 變更狀態
state.count++
}
}
})複製程式碼
呼叫mutation
,需要通過store.commit
方法呼叫mutation type
:
store.commit('increment')複製程式碼
Payload 提交載荷
也可以向store.commit
傳入第二引數,也就是mutation的payload
:
mutaion: {
increment (state, n) {
state.count += n;
}
}
store.commit('increment', 10);複製程式碼
單單傳入一個n
,可能並不能滿足我們的業務需要,這時候我們可以選擇傳入一個payload
物件:
mutation: {
increment (state, payload) {
state.totalPrice += payload.price + payload.count;
}
}
store.commit({
type: 'increment',
price: 10,
count: 8
})複製程式碼
mapMutations函式
不例外,mutations也有對映函式mapMutations
,幫助我們簡化程式碼,使用mapMutations
輔助函式將元件中的methods
對映為store.commit
呼叫。
import { mapMutations } from 'vuex'
export default {
// ...
methods: {
...mapMutations([
'increment' // 對映 this.increment() 為 this.$store.commit('increment')
]),
...mapMutations({
add: 'increment' // 對映 this.add() 為 this.$store.commit('increment')
})
}
}複製程式碼
注 Mutations必須是同步函式。
如果我們需要非同步操作,Mutations就不能滿足我們需求了,這時候我們就需要Actions
了。
Aciton
相信看完之前的Vuex的內容,你就已經入門了。那麼Action就自己進行學習吧(Action有點複雜,我還需要時間消化)。
結語
上個月看Vuex還是一頭霧水,現在看來Vuex也是很容易理解的。
學習一門新技術最重要的就是實踐,單單看教程和demo是遠遠不夠的。
前端路途漫漫,共勉。