以 Vuex 為引,一窺狀態(tài)管理全貌
以下內(nèi)容來自公眾號(hào)逆鋒起筆,關(guān)注每日干貨及時(shí)送達(dá)
作者:楊成功
https://juejin.cn/post/7033682310667239460
-
什么是狀態(tài)管理? -
我為什么要用 Vuex? -
組件內(nèi)部狀態(tài)和 Vuex 狀態(tài)如何分配? -
使用 Vuex 會(huì)有哪些潛在問題?
大綱預(yù)覽
-
狀態(tài)與組件的誕生 -
需要狀態(tài)管理嗎? -
單一數(shù)據(jù)源 -
狀態(tài)更新方式 -
異步更新? -
狀態(tài)模塊化 -
模塊化的槽點(diǎn) -
下一步
狀態(tài)與組件的誕生
-
數(shù)據(jù)驅(qū)動(dòng)視圖 -
組件化
變量。在 數(shù)據(jù)驅(qū)動(dòng) 這個(gè)概念出現(xiàn)之后,一部分變量也被賦予了特殊的含義。
-
組件層級(jí)太深,需要共享狀態(tài),此時(shí)狀態(tài)要層層傳遞。 -
子組件更新一個(gè)狀態(tài),可能有多個(gè)父組件,兄弟組件共用,實(shí)現(xiàn)困難。
需要狀態(tài)管理嗎?
Vuex
創(chuàng)建 store
$ npm install --save vuex
復(fù)制代碼
src/store 文件夾,在這里放所有 Vuex 相關(guān)的代碼。
index.js 并寫入如下代碼。這段代碼主要的作用就是用 Vue.use 方法加載 Vuex 這個(gè)插件,然后將配置好的 Vuex.Store 實(shí)例導(dǎo)出。
import Vue from 'vue'
import Vuex from 'vuex'
// 安裝插件
Vue.use(Vuex)
export default new Vuex.Store({
state: {},
mutations: {},
actions: {},
modules: {}
})
復(fù)制代碼
store。一個(gè) store 中包含了存儲(chǔ)的狀態(tài)(state)和修改狀態(tài)的函數(shù)(mutation)等,所有狀態(tài)和相關(guān)操作都在這里定義。
import store from './store'
new Vue({
el: '#app',
store: store
})
復(fù)制代碼
this.$store 訪問我們導(dǎo)出的 store 實(shí)例。如果不掛載,直接導(dǎo)入使用也是一樣的。
單一數(shù)據(jù)源(state)
Vuex.Store 創(chuàng)建了 store 實(shí)例,大家至少知道該怎么用 Vuex 了。這一步我們來看看 Vuex.Store 構(gòu)造函數(shù)的具體配置。
state 配置,他的值是一個(gè)對(duì)象,用來存儲(chǔ)狀態(tài)。Vuex 使用 單一狀態(tài)樹 原則,將所有的狀態(tài)都放在這個(gè)對(duì)象上,便于后續(xù)的狀態(tài)定位和調(diào)試。
app_version 表示版本,如下:
new Vuex.Store({
state: {
app_version: '0.1.1'
}
}
復(fù)制代碼
this.$store.state.app_version
復(fù)制代碼
import store from '@/store' // @ 表示 src 目錄
store.state.app_version
復(fù)制代碼
this.$store 操作。到了非組件內(nèi),比如在請(qǐng)求函數(shù)中要設(shè)置某一個(gè) Vuex 的狀態(tài),就不知道該怎么辦了。
mapState 函數(shù),它讓獲取多狀態(tài)變得更簡單。
import { mapState } from 'vuex'
export default {
computed: {
... // 其他計(jì)算屬性
...mapState({
version: state => state.app_version
})
}
}
復(fù)制代碼
狀態(tài)更新方式(mutation)
state.app_version='xx' 這種方式修改。Vuex 規(guī)定修改狀態(tài)的唯一方法是提交 mutation。
new Vuex.Store({
state: {
count: 1
},
mutations: {
increment(state, count) {
// 變更狀態(tài)
state.count += count
}
}
})
復(fù)制代碼
this.$store.commit('increment', 2)
復(fù)制代碼
同步更新
異步更新
action 用于異步更新狀態(tài)。與 mutation 不同的是,action 不直接更新狀態(tài),而是通過觸發(fā) mutation 間接更新狀態(tài)。因此即便使用 action 也不違背 “修改狀態(tài)的唯一方法是提交 mutation” 的原則。
new Vuex.Store({
state: {
count: 1
},
mutations: {
add(state) {
state.count++
},
reduce(state) {
state.count--
}
},
actions: {
increment(context, data) {
axios.get('**').then(res => {
if (data.iscan) {
context.commit('add')
} else {
context.commit('reduce')
}
})
}
}
})
復(fù)制代碼
this.$store.dispatch('increment', { iscan: true })
復(fù)制代碼
this.$store.commit 方法觸發(fā) mutation 來更新狀態(tài),完全用不到 action。
狀態(tài)模塊化(module)
new Vuex.Store({
modules: {
user: {
state: {
uname: 'ruims'
},
mutation: {
setName(state, name) {
state.name = name
}
}
}
}
})
復(fù)制代碼
user 模塊,包含了一個(gè) state 和一個(gè) mutation。在組件中使用方法如下:
// 訪問狀態(tài)
this.$store.state.user.uname
// 更新狀態(tài)
this.$store.commit('setName')
復(fù)制代碼
this.$store.state.[模塊名稱] 這種方式去訪問,觸發(fā) mutation 則與全局模塊一樣,沒有區(qū)別。
命名空間
setName 的 mutation。在組件中觸發(fā),哪個(gè) mutation 會(huì)執(zhí)行呢?
namespaced: true 的配置即可開啟,如:
new Vuex.Store({
modules: {
user: {
namespaced: true,
state: {}
}
}
})
復(fù)制代碼
this.$store.commit('user/setName')
復(fù)制代碼
'[mutation]' 變成了 '[模塊名稱]/[mutation]'。
模塊化的槽點(diǎn)
this.$store.user.state.uname
復(fù)制代碼
this.$store.state.user.uname
復(fù)制代碼
this.$store.commit('user/setName')
復(fù)制代碼
this.$store.user.commit('setName')
復(fù)制代碼
為什么吐槽
this.$store.commit 函數(shù)可以觸發(fā)任何 mutation 來更改狀態(tài)。如果一個(gè)組件復(fù)雜,需要操作多個(gè)子模塊的狀態(tài),那么就很難快速的找出當(dāng)前組件操作了哪些子模塊,當(dāng)然也不好做權(quán)限規(guī)定。
b, c 兩個(gè)子模塊的狀態(tài),不允許操作其他子模塊,那么就可以先將要用到模塊導(dǎo)入,比如這樣寫:
import { a, b } from this.$store
export default {
methods: {
test() {
alert(a.state.uname) // 訪問狀態(tài)
a.commit('setName')// 修改狀態(tài)
}
}
}
復(fù)制代碼
下一步
往期精彩
評(píng)論
圖片
表情
