5分鍾讓你掌握Vuex,深入淺出
一、什么是Vuex?
概念:Vuex 是一個專為 Vue.js 應用程序開發的狀態管理模式。它采用集中式存儲管理應用的所有組件的狀態,並以相應的規則保證狀態以一種可預測的方式發生變化。
簡單點來說(說人話),就是實現任意組件中通信,並可以檢測數據的變化。
二、Vuex原理
Vuex是集中於MVC模式中的Model層,規定所有的數據操作必須通過 action - mutation - state
的流程來進行,再結合Vue的數據視圖v-moder等雙向綁定特性來實現頁面的展示更新。
下面看一張圖來了解全過程。
簡述主要方法詳情:
- Vue Components:Vue組件。展示頁面,負責接收用戶操作等交互行為,執行dispatch方法觸發對應action進行回應。
- dispatch:操作行為觸發方法。是唯一能執行action的方法。
- actions:操作行為處理模塊。處理Vue Components接收到的所有交互行為。包含同步/異步操作,支持多個同名方法,按照注冊的順序依次觸發。向后台API請求的操作就在這個模塊中進行,包括觸發其他action以及提交mutation的操作。該模塊提供了Promise的封裝,以支持action的鏈式觸發。
- commit:狀態改變提交操作方法。對mutation進行提交,是唯一能執行mutation的方法。
- mutations:狀態改變操作方法。是Vuex修改state的唯一推薦方法,其他修改方式在嚴格模式下將會報錯。該方法只能進行同步操作,且方法名只能全局唯一。操作之中會有一些hook暴露出來,以進行state的監控等。
- state:頁面狀態管理容器對象。集中存儲Vue components中data對象的零散數據,全局唯一,以進行統一的狀態管理。頁面顯示所需的數據從該對象中進行讀取,利用Vue的細粒度數據響應機制來進行高效的狀態更新。
總的一句話簡述就是:
Vue組件接收交互行為,調用dispatch方法觸發action相關處理,若頁面狀態需要改變,則調用commit方法提交mutation修改state,通過getters獲取到state新值,響應數據或狀態給Vue 組件,界面隨之更新。
三、Vuex的使用
1.安裝
npm install vuex --save
2.新建一個文件夾store,創建inde.js
隨便叫啥,隨便建不建立文件夾。為了規范。
import Vue from 'vue'
import Vuex from 'vuex'
Vue.use(Vuex)
//准備actions---用於響應組件中的動作
const actions={
}
//准備mutations---用於操作數據(state)
const mutations={
}
//准備state---相當於data,用於存儲數據
const state={
}
//實例化創建並導出store
export default new Vuex.Store({
namespaced: true,//解決模塊命名沖突
actions,
mutations,
state,
})
注意:
我們在這一步創建index.js文件的時候導入並引用Vuex,因為我們要實例化Vuex對象。如果在main引入,會導致在main.js導入store的時候報錯。
3.在main.js中引入上一步的index.js,並在實例化 Vue對象時加入 store 對象 :
import store from './store/index' //引入寫好的store
.....
new Vue({
el: '#app',
router,
store,//使用store
template: '',
components: { App }
})
ok,環境搭好,開始操作。
4.簡單使用:
先來一點簡單的存放數據,取出查看。在一系列操作之后我們的VM(View Model)和VC(View component)身上都已經都有store這個數據源對象。所以我們可以從store身上使用this.$store.state.xxx
獲取數據。
在index.js中准備數據
const state={
name:'浪漫主義碼農',
age:18,
}
在組件中獲取數據
<template>
<div>
我放在store中的數據是 {{this.$store.state.name}}, {{this.$store.state.age}}
</div>
</template>
5.mutation、anction
在知道每一個vm和vc身上都有store就可以好好操作了。
mutation--更改store中狀態的唯一方法
根據上面的原理圖,我們能知道vuex中規定只能通過提交mutation的方式去更改store中的狀態,包括action中的操作,也是通過提交mutation去修改。另外一點就是vuex中規定mutation中不能包含異步操作
我們來修改上面的name、age屬性。
const mutations = {
modify_age(state) {//不帶參數修改age屬性,state是默認的參數
state.name = "張三";
state.age = 20;
},
modify_age2(state,payload) {//帶參數修改,payload是傳入的對象,官網叫載荷(payload)
state.name=payload.name;
state.age=payload.age;
}
}
在組件中,我們要使用this.$store.commit('xxx(方法名)', 參數;
參數可以是對象也可以是單一屬性
<template>
<div>
我放在store中的數據是 {{ this.$store.state.name }},
{{ this.$store.state.age }}
<button @click="setDefault">不帶參修改</button>
<button @click="setparameter">帶參修改</button>
</div>
</template>
<script>
export default {
methods: {
setDefault() {
this.$store.commit("modify_age");
},
setparameter() {
this.$store.commit("modify_age2",{name:"王五",age:100});//載荷形式,傳入可以使對象或者單個屬性
// this.$store.commit({//對象形式,傳入可以使對象或者單個屬性
// type: "modify_age2",
// name: "王五",
// age: 100,
// });
});
},
},
};
</script>
anction--同步/異步更改狀態
Action 類似於 mutation,不同在於:
- Action 提交的是 mutation,而不是直接變更狀態。
- Action 可以包含任意異步操作。
后台API請求在這個模塊進行請求。所有的操作最后都要到達mutation進行操作,更改state的狀態。
還是上面一個例子,異步修改state的屬性
先上代碼
const actions = {
asy_modify (context) {//無參
setTimeout(() => {//異步操作
context.commit("modify_age")
}, 2000);
},
asy_modify2 (context,plyload) {//有參
setTimeout(() => {
context.commit("modify_age2",plyload);
}, 2000);
}
}
const mutations = {
modify_age(state) {//不帶參數修改age屬性,state是默認的參數
state.name = "張三";
state.age = 20;
},
modify_age2(state,payload) {//帶參數修改,payload是傳入的對象,官網叫載荷(payload)
state.name=payload.name;
state.age=payload.age;
}
}
const state = {
name: '浪漫主義碼農',
age: 18,
}
在組件中使用this.$store.dispatch('xxx')
<template>
<div>
我放在store中的數據是 {{ this.$store.state.name }},
{{ this.$store.state.age }}
<button @click="setDefault">不帶參修改</button>
<button @click="setparameter">帶參修改</button>
</div>
</template>
<script>
export default {
methods: {
setDefault() {
this.$store.dispatch("asy_modify");
},
setparameter() {
this.$store.dispatch("asy_modify2",{name:"王五",age:100});//載荷形式,傳入可以使對象或者單個屬性
// this.$store.dispatch({//對象形式,傳入可以使對象或者單個屬性
// type: "asy_modify2",
// name: "王五",
// age: 100,
// });
},
},
};
</script>
注意觀察時間,2s后變化。
分析一波:
-
Action 里面的函數接受一個與 store 實例具有相同方法和屬性的 context 對象,因此你可以調用
context.commit
提交一個 mutation,或者通過context.state
和context.getters
來獲取 state 和 getters。 -
action事件的觸發同樣可以使用載荷和對象兩種方式
6. getter
getter,我們可以理解為是對store中state的一些派生狀態,也可以理解為一種計算屬性,它類似於計算屬性一樣,返回值會根據它的依賴被緩存起來,且依賴對象發生改變的時候它才會被重新計算。
getter屬性相當於很多個組件需要對數據進行一樣的處理,可以理解為公共的計算屬性。
這樣就很清晰了
Getter 接受 state 作為其第一個參數,也可以使用箭頭函數。
const getters = {
get_object: function (state) {//無參
if (state.age < 18) {
return state.name + '未成年'
}
return state.name + '已經成年了'
},
get_object2: function (state) {//有參數
return function(value){
return state.name + value;
}
}
}
組件中{this.$store.getters.xxx
來獲取
<template>
<div>
我放在store中的數據是 {{ this.$store.state.name }},
{{ this.$store.state.age }}
<br>
<span>不帶參數的數據:{{ this.$store.getters.get_object }}</span>
<br>
<span>帶參數的數據(攜帶一個剛好18歲):{{
this.$store.getters.get_object2("剛好18歲")
}}</span>
</div>
</template>
7.Modoules
Vuex 允許我們將 store 分割成模塊(module)。每個模塊擁有自己的 state、mutation、action、getter、甚至是嵌套子模塊。這里就不過多介紹了,看官方文檔(Module | Vuex (vuejs.org))
8.輔助函數
vuex提供了幾個的輔助函數,有mapState、mapGetter、mapMutation、mapAction。都是一些復雜語句的簡寫形式。
引入函數
import {mapState,mapGetters,mapMutation,mapAction} from 'vuex'
mapState
如果state中的數據很多,那我們要重復寫很多這樣的this.$store.state.XXX
代碼,我們就可以通過mapState來映射。
數組的寫法
export default {
computed:{
...mapState(['name','age'])//自動就添加到了計算屬性中,此時就可以直接像訪問計算屬性一樣訪問它
}
};
如果你想取名別名的話,就要寫成對象的形式
...mapState(
{
myname: 'name',
myage: "age",
}
mapGetters
mapGetters和mapState很相似,只不過是映射Getters。替代this.$store.getters.XXX
computed: {
...mapGetters(['get_object','get_object2']),//數組形式寫法
...mapGetters({get1:'get_object',get2:'get_object2'})//可以取別名,對象形式寫法
},
mapMutation
替代this.$store.commit('XXX')
methods: {
...mapMutations(['modify_age','modify_age2']),//數組形式寫法
...mapMutations({modify:'modify_age',modify2:'modify_age2'}),//可以取別名,對象形式寫法
},
mapAction
替代this.$store.dispatch('XXX')
methods: {
...mapActions(['asy_modify','asy_modify2']),//數組形式寫法
...mapActions({act_modify:'asy_modify',act_modify2:'asy_modify2'})//對象形式寫法
},
以上這些輔助函數,涉及到傳參都需在使用的計算屬性的時候傳入。
四、寫在最后
更具體的請看官網文檔,歡迎各位大佬指點江山。
看到最后點贊收藏吧!