前言
在用vue作為前端框架進行開發的時候,對於元件間的傳值你一定不會陌生,如果只是簡單的父子元件傳值,我想你肯定不會選擇用Vuex來進行狀態管理,但是如果你需要構建一箇中大型單頁應用,元件間資料互動比較複雜頻繁,你很可能會考慮如何更好地在元件外部管理狀態,那麼Vuex 將會成為自然而然的選擇。
Vuex 是什麼?
Vuex 是一個專為 Vue.js 應用程式開發的狀態管理模式。它採用集中式儲存管理應用的所有元件的狀態,並以相應的規則保證狀態以一種可預測的方式發生變化。 這是官方的一種說法。
用個人的話總結下:Vuex就是為了實現多元件資料共享,從而建立一個叫store的資料管理庫,將需要共享的資料存放在裡面,在需要的地方可以取出來作為初始資料,也可以在元件內通過dispatch或者提交commit方法來改變該原始資料狀態,從而實現的data的共享。
Vuex的核心
1、 State
Vuex中的資料來源,我們需要儲存的資料就儲存在這裡,可以在頁面通過this.$store.state來獲取我們定義的資料。
import Vue from "vue";
import Vuex from "vuex";
Vue.use(Vuex);
const state = {
number: 0
}
export default new Vuex.Store({
state,
});
複製程式碼
在頁面中通過this.$store.state.number 即可獲取到當前的值。
2、Getter
Vuex 允許我們在 store 中定義“getter”(可以認為是 store 的計算屬性)。就像計算屬性一樣,getter 的返回值會根據它的依賴被快取起來,且只有當它的依賴值發生了改變才會被重新計算。
Getter 接受 state 作為其第一個引數:
import Vue from "vue";
import Vuex from "vuex";
Vue.use(Vuex);
const state = {
number: 0
}
const getters = {
getNumber(state) {
return state.number + 1
}
}
export default new Vuex.Store({
state,
getters,
});
複製程式碼
在頁面你可以用兩種方式取到getters裡面的值
1、通過屬性訪問
Getter 會暴露為 store.getters 物件,你可以以屬性的形式訪問這些值 如: this.$store.getters.getNumber
Getter 也可以接受其他 getter 作為第二個引數:
const state = {
number: 1
}
const getters = {
getNumber(state) {
return state.number + 1 // 2
},
getDoubNUmber(state, getters) {
return state.number + getters.getNumber // 3
}
}
複製程式碼
注意: getter 在通過屬性訪問時是作為 Vue 的響應式系統的一部分快取其中的。
2、 通過方法訪問
你也可以通過讓 getter 返回一個函式,來實現給 getter 傳參。在你對 store 裡的陣列進行查詢時非常有用。
const state = {
number: 1,
list: [1, 2, 3, 4, 5]
}
const getters = {
getNumber(state) {
return state.number + 1 // 2
},
getDoubNumber(state, getters) {
return state.number + getters.getNumber // 3
},
filterNumber:(state)=>(num)=> {
return state.list.find(item=> item%num === 0)
}
}
export default new Vuex.Store({
state,
getters,
});
複製程式碼
注意,getter 在通過方法訪問時,每次都會去進行呼叫,而不會快取結果 this.$store.getters.filterNumber(3)
3、Mutation
更改 Vuex 的 store 中的狀態的唯一方法是提交 mutation。Vuex 中的 mutation 非常類似於事件:每個 mutation 都有一個字串的 事件型別 (type) 和 一個 回撥函式 (handler)。這個回撥函式就是我們實際進行狀態更改的地方,並且它會接受 state 作為第一個引數, 提交載荷(payload) 作為額外的引數,並且在大多數情況下,載荷應該是一個物件,這樣可以包含多個欄位並且使記錄的 mutation 會更易讀:
你可以這樣寫:
const mutations = {
increment(state, n) {
state.number += n
}
}
複製程式碼
但你不能直接呼叫一個 mutation handler。這個選項更像是事件註冊:“當觸發一個型別為 increment 的 mutation 時,呼叫此函式。”要喚醒一個 mutation handler,你需要以相應的 type 呼叫 store.commit 方法:
this.$store.commit('increment', 1)
複製程式碼
也可以這樣寫:
const mutations = {
increment(state, payload) {
state.number += payload.count
}
}
複製程式碼
然後:
使用 this.$store.commit('increment', {count: 1}) 提交,
// 或者另一種方式是直接使用包含 type 屬性的物件進行提交:
this.$store.commit({
type: 'increment',
count: 1
})
複製程式碼
特別說明:在 Vuex 中,mutation 都是同步任務: 為了處理非同步操作,讓我們來看一看 Action。
4、 Action
Action 類似於 mutation,不同在於:
1、Action 提交的是 mutation,而不是直接變更狀態。
2、Action 可以包含任意非同步操作。
雖然在頁面中通過提交commit是可以達到修改store中狀態值的目的,但是官方並不建議我們這樣做,而是讓我們去提交一個action,在action中提交mutation再去修改狀態值。
const mutations = {
increment(state) {
state.number += 1
}
}
const actions = {
addNumber(context){
context.commit('increment')
}
}
複製程式碼
Action 函式接受一個與 store 例項具有相同方法和屬性的 context 物件,因此你可以呼叫 context.commit 提交一個 mutation,或者通過 context.state 和 context.getters 來獲取 state 和 getters
addNumber( {commit} ){
commit('increment')
}
以上這種寫法等同於:
addNumber(context){
context.commit('increment')
}
複製程式碼
Action 通過 store.dispatch 方法觸發:
this.$store.dispatch('addNumber')
複製程式碼
同mutation 一樣你也可以在action的時候傳遞引數
const mutations = {
increment(state, number) {
state.number += number
}
}
const actions = {
addNumber(context, number){
context.commit('increment', number)
}
或者:
addNumber( {commit}, number){
commit('increment', number)
}
}
觸發方法: this.$store.dispatch('addNumber', 10)
複製程式碼
關於在action 處理非同步操作可以看下面這個例子:
const actions = {
getData({commit}) {
return new Promise((resolve, reject)=> {
setTimeout(()=>{
commit('getList')
resolve()
}, 1000)
})
}
}
複製程式碼
然後再
this.$store.dispatch('getData').then(() => {
// ...
})
複製程式碼
完整 例項:
import Vue from "vue";
import Vuex from "vuex";
import { resolve, reject } from "any-promise";
Vue.use(Vuex);
const state = {
number: 1,
list: [1, 2, 3, 4, 5]
}
const getters = {
getNumber(state) {
return state.number + 1 // 2
},
getDoubNumber(state, getters) {
return state.number + getters.getNumber // 3
},
filterNumber:(state)=>(num)=> {
return state.list.find(item=> item%num === 0)
}
}
const mutations = {
increment(state, n) {
state.number += n
},
getList(state) {
state.list = state.list.forEach((item)=> item*2)
}
}
const actions = {
addNumber( {commit} , n){
commit('increment', n)
},
getData({commit}) {
return new Promise((resolve, reject)=> {
setTimeout(()=>{
commit('getList')
resolve()
}, 1000)
})
}
}
export default new Vuex.Store({
state,
getters,
mutations,
actions
});
複製程式碼
關於 Vuex中mapState、mapGetters、mapMutations、mapActions的用法
要用 首先得引入:
import { mapState, mapGetters, mapMutations, mapActions } from 'vuex';
複製程式碼
這玩意兒其實就是Vuex 內建的輔助函式,方便我們獲取store裡面的資料和方法
computed: {
...mapState([
'number'
])
}
複製程式碼
// 使用物件展開運算子將 getter 混入 computed 物件中
computed: {
...mapGetters([
'getNumber',
'getDoubNumber',
// ...
])
}
複製程式碼
methods: {
...mapMutations([
'increment', // 將 `this.increment()` 對映為 `this.$store.commit('increment')`
...mapMutations({
add: 'increment' // 將 `this.add()` 對映為 `this.$store.commit('increment')`
})
}
複製程式碼
methods: {
...mapActions([
'addNumber', // 將 `this.addNumber()` 對映為 `this.$store.dispatch('addNumber')`
// `mapActions` 也支援載荷:
'addNumber' // 將 `this.addNumber(amount)` 對映為 `this.$store.dispatch('addNumber', amount)`
]),
...mapActions({
requestData: 'getData' // 將 `this.requestData()` 對映為 `this.$store.dispatch('getData')`
})
}
複製程式碼
以上是對Vuex實現狀態管理的一個整個過程的理解,參考官方文件,然後自己寫一遍,比較容易明白其中的道理,後面有時間想寫React裡面關於Redux實現狀態管理的一個過程,對比其中,其實他們思想差不多, 只不過redux實現過程更多點,敬請期待!