什么是Vuex,有什么用?
Vuex 是一個專為 Vue.js 應用程序開發的狀態管理模式。
普通的Vue狀態自管理在遇到多個視圖共同依賴同一狀態,或者會改變同一狀態時,會遇到難以管理,難以維護的麻煩。為了解決這個麻煩,Vue官方基於全局單例模式提供了Vuex狀態管理框架。
在Vuex框架中,Vue視圖,狀態,數據之間的關系如下圖所示:
什么時候應該使用Vuex,什么時候不要使用?
如果您不打算開發大型單頁應用,使用 Vuex 可能是繁瑣冗余的。確實是如此——如果您的應用夠簡單,您最好不要使用 Vuex。一個簡單的 store 模式就足夠您所需了。但是,如果您需要構建一個中大型單頁應用,您很可能會考慮如何更好地在組件外部管理狀態,Vuex 將會成為自然而然的選擇。
如何使用Vuex
創建一個Vuex的狀態管理倉庫
- 安裝Vuex框架:
我們通過如下命令為Vue項目中添加Vuex框架
npm i Vuex
如下圖所示:
2. 在main.js中引入Vuex框架,並通過use命令加載到Vue中
import Vuex from 'vuex'
Vue.use(Vuex)
- 創建一個store倉庫,並把store倉庫注冊到Vue全局中;store倉庫包含state(單一狀態樹,提供響應式數據),getters(store的計算屬性),mutations(改變store狀態的方法),actions(處理異步操作,觸發mutation)
const store = new Vuex.Store({
state:{
},
mutations:{
},
actions:{
},
getters:{
}
})
new Vue({
store,
render: h => h(App),
}).$mount('#app')
mutations
更改 Vuex 的 store 中的狀態的唯一方法是提交 mutation。Vuex 中的 mutation 非常類似於事件:每個 mutation 都有一個字符串的 事件類型 (type) 和 一個 回調函數 (handler)。這個回調函數就是我們實際進行狀態更改的地方,並且它會接受 state 作為第一個參數.
你不能直接調用一個 mutation handler。這個選項更像是事件注冊:“當觸發一個類型為 increment 的 mutation 時,調用此函數。”要喚醒一個 mutation handler,你需要以相應的 type 調用 store.commit 方法
actions
Action 類似於 mutation,不同在於:
- Action 提交的是 mutation,而不是直接變更狀態。
- Action 可以包含任意異步操作。
- Action的分發使用關鍵字
- 為store倉庫創建單一狀態樹State,並創建mutations方法修改state
const store = new Vuex.Store({
state:{
count:0
},
mutations:{
increment(state,n){
state.count+=n
console.log(state.count)
}
},
actions:{
},
getters:{
}
})
- 到此為止,Vue中的組件就可以使用store狀態倉庫了。因為在main.js中,我們通過new Vue將store倉庫注冊到Vue全局中,所以我們在模板中可以通過this.$store的方式獲取到我們store倉庫。下面的示例展示了通過組件的計算屬性computed定義count變量並通過模板語法展現store狀態倉庫中的count值。
<template>
<div id="app">
{{count}}
</div>
</template>
<script>
export default {
name: 'App',
components: {
},
computed:{
count(){
return this.$store.state.count
}
},
methods:{
}
}
效果如下:
6. 我們當然可以修改store的count值。我們先采用以前的模板事件來修改。
<template>
<div id="app">
{{count}}
<input type="button" @click="handleClick" value="Count++" />
</div>
</template>
<script>
export default {
name: 'App',
components: {
},
computed:{
count(){
return this.$store.state.count
}
},
methods:{
handleClick(){
return this.$store.state.count++;
}
}
}
</script>
效果如下:
7. 但是Vue並不鼓勵我們采用這樣的方式來修改store的count值。這樣管理依然不方便,很有可能造成混亂。按照上面對mutations的介紹,我們可以猜到Vuex鼓勵我們通過mutations對store的state進行修改,這樣我們對state的修改過程才會被Vuex記錄下來。我們先前在初始化state時,同步初始化了mutations:我們創建了一個叫increment的方法,現在我們只需要調用這個方法即可。每一個mutations中的方法本質都是一個回調函數,處理sate狀態的邏輯都包含在里面,接收state參數。mutations方法可以多接收一個額外參數(提交荷載),如果希望傳入多個數據,則應該組織成對象再傳入(示例中僅僅是一個簡單的number)
mutations:{
increment(state,n){
state.count+=n
console.log(state.count)
}
},
- Vuex中的mutations方法不能被直接調用,必須被actions或模板以commit的形式調用。我們先嘗試使用模板直接commit的形式調用(假設我們沒有異步操作需要處理,完全可以繞過actions)
<template>
<div id="app">
{{count}}
<input type="button" name="count2" @click="$store.commit('increment',2)" value="Count+2" />
</div>
</template>
<script>
export default {
name: 'App',
components: {
},
computed:{
count(){
return this.$store.state.count
}
},
methods:{
}
}
</script>
<style>
</style>
- 我們通過click事件直接對store進行了commit操作,commit調用時傳入了兩個參數,第一個是回調函數名:increment,另一個是提交荷載:一個整數;效果如下:
- 到此為止,我們一直是使用的Vue組件的compute屬性展示的sotre。如果有多個組件需要用到此屬性,我們要么復制這個函數,或者抽取到一個共享函數然后在多處導入它——無論哪種方式都不是很理想。先前介紹過:getters是sotre的computer,那么我們完全可以在sotre的getters中處理展示邏輯。
const store = new Vuex.Store({
state:{
count:0
},
mutations:{
increment(state,n){
state.count+=n
console.log(state.count)
}
},
actions:{
},
getters:{
doubleCount(state){
return state.count * 2
}
}
})
<template>
<div id="app">
{{$store.getters.doubleCount}}
<input type="button" name="count2" @click="$store.commit('increment',2)" value="Count+2" />
</div>
</template>
<script>
export default {
name: 'App',
components: {
},
computed:{
},
methods:{
}
}
</script>
<style>
</style>
效果如下:
11. 我們一直還沒有使用到store的actions。根據官網描述,actions與mutation很像,不同的是用來觸發(commit)mutation而不是直接修改狀態,最重要的是我們可以在actions中處理異步邏輯,調用遠程API等等(如下示例中,利用模擬異步等待);前台調用是使用dispatch關鍵字調用。
const store = new Vuex.Store({
state:{
count:0
},
mutations:{
increment(state,n){
state.count+=n
console.log(state.count)
}
},
actions:{
increment(state,n){
setTimeout(() => {
state.commit('increment',n)
},1000);
}
},
getters:{
doubleCount(state){
return state.count * 2
}
}
})
<template>
<div id="app">
{{$store.getters.doubleCount}}
<input type="button" name="count1" @click="$store.dispatch('increment',3)" value="Count+3" />
</div>
</template>
<script>
export default {
name: 'App',
components: {
},
computed:{
},
methods:{
}
}
</script>
<style>
</style>
效果如下: