Vue之vuex狀態(tài)管理
Vuex 是一個專為 Vue.js 應用程序開發(fā)的狀態(tài)管理模式没陡。
這個Vuex包含以下幾個屬性部分:
Action:和mutation的功能大致相同
State:vuex的基本數(shù)據(jù),用來存儲變量
Mutation:提交更新數(shù)據(jù)的方法咆蒿,必須是同步的(如果需要異步使用action)久窟。每個 mutation 都有一個字符串 的 事件類型 (type) 和 一個 回調(diào)函數(shù) (handler)秩冈。
Module:模塊化vuex,可以讓每一個模塊擁有自己的state斥扛、mutation入问、action、getters,使得結(jié)構(gòu)非常清晰稀颁,方便管理
Getter:從基本數(shù)據(jù)(state)派生的數(shù)據(jù)芬失,相當于state的計算屬性
那么好的我們Actions
開始講起
1.Action
Action 類似于 mutation,不同在于:
- Action 提交的是 mutation匾灶,而不是直接變更狀態(tài)棱烂。
- Action 可以包含任意異步操作。
我們先來注冊一個action
state: {
count: 0
},
mutations: {
add (state) {
state.count++
},
decrease (state) {
state.count--
}
},
actions: {
delayAdd (context) {
setTimeout(() => {
//通過context提交一個mutation
context.commit('add')
}, 1000)
}
},
Action 函數(shù)接受一個與 store 實例具有相同方法和屬性的 context 對象阶女,因此你可以調(diào)用 context.commit
提交一個 mutation颊糜,或者通過 context.state
和 context.getters
來獲取 state 和 getters。
Action 通過 store.dispatch
方法或者用輔助函數(shù)mapActions
觸發(fā):
// 以載荷形式分發(fā)
store.dispatch('add', {
amount: 10
})
// 以對象形式分發(fā)
store.dispatch({
type: 'add',
amount: 10
})
很多時候我們一般使用commit比較多秃踩,但是又不想引入context,我們更多時候采用參數(shù)結(jié)構(gòu)的方式
actions: {
delayAdd ({ commit }) {
commit('add')
}
}
我們一直說Action 通常是異步的衬鱼,那么如何知道 action 什么時候結(jié)束呢?更重要的是憔杨,我們?nèi)绾尾拍芙M合多個 action鸟赫,以處理更加復雜的異步流程?
store.dispatch
可以處理被觸發(fā)的 action 的處理函數(shù)返回的 Promise芍秆,并且 store.dispatch
仍舊返回 Promise:
舉個栗子
actions: {
actionA ({ commit }) {
return new Promise((resolve, reject) => {
setTimeout(() => {
commit('someMutation')
resolve()
}, 1000)
})
}
}
我們?nèi)ナ褂糜|發(fā)的時候
store.dispatch('actionA').then(() => {
// ...
})
或者別的地方我們還想用
actions: {
// ...
actionB ({ dispatch, commit }) {
// 等待A
return dispatch('actionA').then(() => {
commit('someOtherMutation')
})
}
}
當然了有了async和await以后更方便
// 假設 getData() 和 getOtherData() 返回的是 Promise
actions: {
async actionA ({ commit }) {
// 提交getData(),等待返回結(jié)果
commit('gotData', await getData())
},
async actionB ({ dispatch, commit }) {
await dispatch('actionA') // 等待 actionA 完成
commit('gotOtherData', await getOtherData())
}
}
2.State
單一狀態(tài)值
我們在Vue組件中要讀取Vuex中的狀態(tài)值一般有兩種方式
第一種方式: this.$store.state
注釋:這里讀取的就是上面state進行存放的值
<template>
<div class="home">
<h3>This is an home page</h3>
<div style="color: red">{{count}}</div>
</div>
</template>
<script>
// @ is an alias to /src
export default {
name: 'home',
// 一般在計算屬性里面去監(jiān)聽處理數(shù)據(jù)值
computed: {
count () {
// 通過this.$store.state去讀取存放的變量值
return this.$store.state.count
}
},
}
</script>
第二種方式: mapState輔助函數(shù)
官方文檔中給的mapState函數(shù)里惯疙,給了三種獲取方式
computed: mapState({
// 第一種我們使用箭頭函數(shù)
count: state => state.count,
// 第二種傳字符串'count'等同于上面'state => state.count'(建議使用)
countAlias: 'count'
// 為了能夠使用 `this` 獲取局部狀態(tài),必須使用常規(guī)函數(shù)
countPlusLocalState (state) {
return state.count + this.localCount
}
})
我們這里寫了代碼采用了第二種方式妖啥,也是我個人經(jīng)常用的一種
<template>
<div class="home">
<h3>This is an home page</h3>
<div style="color: red">{{count}}</div>
</div>
</template>
<script>
// 第一步先引入mapState函數(shù)
import { mapState } from 'vuex'
export default {
name: 'home',
// 第二步去使用這個函數(shù)
computed: mapState({
// 通過傳字符串的方式取值
count: 'count'
})
}
</script>
當然了霉颠,我們要知道es6的語言魅力很多,當映射的計算屬性的名稱與 state 的子節(jié)點名稱相同時荆虱,我們也可以給 mapState
傳一個字符串數(shù)組蒿偎。
P嗝恰!诉位!切記這是一個數(shù)組哦骑脱,不要寫成了大括號{}
computed: mapState([
// 映射 this.count 為 store.state.count
'count'
])
可能接下來有同學就會問,如果我既要使用計算屬性苍糠,又要用mapState呢
那么接下來我們可能會用到這個對象展開符: 嘻嘻叁丧,傳說中的點點點...
舉個栗子
computed: {
localComputed () { /* ... */ },
// 使用對象展開運算符將此對象混入到外部對象中
...mapState([
'count'
])
}
3.Mutation
我們介紹這個之前我們首先要明白的是:更改 Vuex 的 store 中的狀態(tài)的唯一方法是提交 mutation
mutation 必須是同步函數(shù)
前面講Actions的時候我們已經(jīng)在mutations里面封裝了加減函數(shù),接下來我就要說組件里面怎么去提交mutation,去更改Vuex的store中的狀態(tài)
第一種方式:組件上綁定一個方法,然后在方法里面去提交mutation
<template>
<div class="home">
<h3>This is an home page</h3>
<div style="color: red">{{count}}</div>
<button @click="add">增加count</button>
</div>
</template>
<script>
import { mapState } from 'vuex'
export default {
name: 'home',
computed: {
...mapState({
count: 'count'
})
},
methods: {
add () {
// 點擊觸發(fā)提交給Mutation,觸發(fā)add方法
this.$store.commit('add')
}
}
}
</script>
第二種方式:還是繼續(xù)使用輔助函數(shù)岳瞭,嘿嘿用起來以后真香拥娄,這次這個函數(shù)叫mapMutations
methods: {
...mapMutations([
'increment', // 將 `this.increment()` 映射為 `this.$store.commit('increment')`
// `mapMutations` 也支持載荷(傳多個參數(shù)):
// 將 `this.incrementBy(amount)` 映射為 `this.$store.commit('incrementBy', amount)`
'incrementBy'
]),
...mapMutations({
add: 'increment' // 將 `this.add()` 映射為 `this.$store.commit('increment')`
})
}
一些其他的知識點:
提交載荷(Payload)
定義:store.commit
傳入額外的參數(shù),即 mutation 的 載荷(payload)
1.比如我們在mutations中定義
mutations: {
// 此處我們傳入多個參數(shù)
increment (state, n) {
state.count += n
}
}
提交的時候就是這樣了
store.commit('increment', 10)
2.但更多時候我們載荷是一個對象
舉個栗子
mutations: {
// 這里payload是一個對象
increment (state, payload) {
state.count += payload.amount
}
}
// 第一種方式
store.commit('increment', {
amount: 10
})
// 第二種方式
store.commit({
type: 'increment',
amount: 10
})
使用常量替代 Mutation 事件類型
為什么會來介紹這個呢瞳筏,我們想想一般比較大型的項目稚瘾,人員多,mutation里面的方法眾多姚炕,我們定義一個常量方法摊欠,在store.js中引用,去mutation中使用柱宦,統(tǒng)一的去管理些椒,是不是給人更清晰直觀的感受更容易知道
// 我們隨便選擇新建一個管理的js,比如叫mutation-types.js,我們在這里去新建mutation的方法捷沸,統(tǒng)一管理
export const ADD_MUTATION = 'ADD_MUTATION'
export const Delete_MUTATION = 'Delete_MUTATION'
//我們在store.js里面要去引用這個常量
import {ADD_MUTATION, Delete_MUTATION} from './mutation-types.js'
mutations: {
// 我們可以使用 ES6 風格的計算屬性命名功能來使用一個常量作為函數(shù)名
[ADD_MUTATION] (state) {
// 進行增加操作啊
}
[Delete_MUTATION] (state) {
// 進行刪除操作
}
}
4.Module
使用單一狀態(tài)樹摊沉,應用的所有狀態(tài)會集中到一個比較大的對象。當應用變得非常復雜時痒给,store 對象就有可能變得相當臃腫说墨。
為了解決以上問題,Vuex 允許我們將 store 分割成模塊(module)苍柏。每個模塊擁有自己的 state尼斧、mutation、action试吁、getter棺棵、甚至是嵌套子模塊——從上至下進行同樣方式的分割:
const moduleA = {
state: { ... },
mutations: { ... },
actions: { ... },
getters: { ... }
}
const moduleB = {
state: { ... },
mutations: { ... },
actions: { ... }
}
// 放進store中
const store = new Vuex.Store({
modules: {
a: moduleA,
b: moduleB
}
})
store.state.a // -> moduleA 的狀態(tài)
store.state.b // -> moduleB 的狀態(tài)
我們可以到這便是簡單基礎的模塊劃分,更多的時候熄捍,我們一般才用的是多個文件烛恤,比如a.js里面我就寫moduleA,b.js里面我就寫moduleB,然后給導出,最后統(tǒng)一在index.js引入余耽,在總模塊中使用
5.Getter
從基本數(shù)據(jù)(state)派生的數(shù)據(jù)缚柏,相當于state的計算屬性
便于多個組件使用,也是在組件的computed屬性中讀取this.$store.getters
1.通過對象來訪問
state: {
todos: [
{ id: 1, text: '...', done: true },
{ id: 2, text: '...', done: false }
]
},
getters: {
// Getter接受state作為其第一個參數(shù)
doneTodos: state => {
return state.todos.filter(todo => todo.done)
}
/** Getter 也可以接受其他 getter 作為第二個參數(shù): **/
doneTodosCount: (state, getters) => {
// 這里我們?nèi)プx取第一個doneTodos里面的參數(shù)
return getters.doneTodos.length
}
}
computed: {
doneTodos () {
// 通過this.$store.getters來獲取
return this.$store.getters.doneTodos
}
},
2.通過方法來訪問
通過讓 getter 返回一個函數(shù)碟贾,來實現(xiàn)給 getter 傳參币喧。在你對 store 里的數(shù)組進行查詢時非常有用轨域。
state: {
todos: [
{ id: 1, text: '...', done: true },
{ id: 2, text: '...', done: false }
]
},
getters: {
// 目的就是方便我去查詢state里面存放的值
getTodosId: (state) => (id) => {
return state.todos.find(todo => todo.id === id)
}
},
3.輔助函數(shù)mapGetters
// 在組件中引入輔助函數(shù)mapGetters
import {mapgetters} from 'vuex'
// 在組件的computed里面
computed: {
//同名的話
...mapGetters([
'doneTodos'
])
//或者你想換個名字
...mapGetters({
doneTodos: 'doneTodos'
})
},
換名字采用的是對象的形式:所以要記得用{}