Vue 學習筆記 05——狀態管理Vuex

Vuex 是一個專爲 Vue.js 應用程序開發的狀態管理模式。它採用集中式存儲管理應用的所有組件的狀態,並以相應的規則保證狀態以一種可預測的方式發生變化。流程如下官網圖所示:

基礎知識

1.  store 

Vuex 的核心就是 store(倉庫),它就像一個容器,包含着應用中大部分的狀態 state .Vuex與全局對象的不同在於:

1)Vuex狀態存儲爲響應式的,store中的狀態發生改變時,相應的組件也會更新

2)不能直接改變store中的state,唯一途徑是顯示的提交(commitmutation。這樣方便跟蹤每一個狀態的變化

 

2.  簡單的創建store

1)在main.js中引入創建store

     * 創建後可以通過 store.state 來獲取狀態對象,以及通過 store.commit 方法觸發狀態變更

import Vue from 'vue'
import Vuex from 'vuex'

const store = new Vuex.Store({
  state: {
    count: 0
  },
  mutations: {
    increment (state) {
      state.count++
    }
  }
})

 2) 然後在Vue實例中,提供創建好的store,如此便可在組件中訪問到this.$store中的property

new Vue({
  el: '#app',
  store: store,
})

3)現在可以在計算屬性computed中,返回狀態

computed:{
    count(){
        return this.$store.state.count;
    }
}

4)當狀態需要改變時,可通過在組件的 methods提交(commit) mutation

methods: {
  increment() {
    this.$store.commit('increment')
    console.log(this.$store.state.count)
  }
}

3.四個核心概念

1)State

     a)所有的狀態定義在state對象中;

     b)從 store 實例中 讀取狀態 最簡單的方法就是在 計算屬性 中返回某個狀態;

     c)Vuex提供一種機制將狀態從根組件“注入”到每一個子組件中( 需要調用Vue.use(Vuex) ):

const app = new Vue({
  el: '#app',
  // 把 store 對象提供給 “store” 選項,這可以把 store 的實例注入所有的子組件
  store,
  components: { Counter },
  template: `
    <div class="app">
      <counter></counter>
    </div>
  `
})

       通過根實例註冊的store,改store實例會注入到根組件下的所有子組件,且子組件能通過this.$store訪問到,如下:

const Counter = {
  template: `<div>{{ count }}</div>`,
  computed: {
    count () {
      return this.$store.state.count
    }
  }
}

     d)輔助函數 mapState

           當一個組件要獲取多個狀態的時候,可使用  mapState 輔助函數幫助我們生成計算屬性,這樣簡潔一些。

           當映射的計算屬性的名稱與 state 的子節點名稱相同時,我們也可以給 mapState 傳一個字符串數組。

import { mapState, mapGetters } from 'vuex'

...
computed:{
	...mapState(['userInfo']),
	...mapGetters(['memberInfo'])
},
...

2)Getter

可以理解爲是獲取數據的,有時候我們需要從 store 中的 state 中派生出一些狀態,例如根據userState的值顯示用戶等級:

  a)Getter 接受 state 作爲其第一個參數

export default{
	memberInfo(state){
		switch (state.userStatus){
			case 0:
					return '普通會員';
					break;
			case 1:
					return 'VIP會員';
					break;		
			case 2:
					return '高級V'+ state.vipLevel +'會員';
					break;
			default:
					return '普通會員';
					break;

		}

	}
}

   b)使用時,也可用輔助函數 mapGetters

3)Mutation

      a)它是更改 Vuex store 中狀態的唯一方法是提交 mutation. 而 mutation 類似一個事件,每一個 mutation 都有一個字符串的事件類型和一個回調函數,回調函數就是我們狀態要進行更改的地方,並且它會接受 state 作爲第一個參數。

      b)Mutation 必須是同步函數

例如:登錄後修改userStatus

//登錄組件的login()中
//commit中有兩個參數
//第一個參數,對應的是mutation中的函數名
//第二個參數,多數情況下是一個對象
self.$store.commit('setMemberInfo',{
	userStatus:0,
	vipLevel:0
});
//mutations.js中
export default{
	//登錄調用,重置用戶信息
	login(state, v){
		state.userInfo = v;
	},

	//重新修改用戶等級狀態
    //第一個參數接收state
    //第二個參數接收組件中commit傳來的值
	setMemberInfo(state,v){
		state.userStatus = v.userStatus;
		state.vipLevel =v.vipLevel;
	}
}

4)Action

Action 類似於 mutation,不同在於:

  • Action 提交的是 mutation,而不是直接變更狀態。
  • Action 可以包含任意異步操作。

 a)註冊一個簡單的 action:

const store = new Vuex.Store({
  state: {
    count: 0
  },
  mutations: {
    increment (state) {
      state.count++
    }
  },
  actions: {
    increment (context) {
      context.commit('increment')
    }
  }
})

由於 Action函數 接收一個 與store實例具有相同方法和屬性 context 對象,因此可以用context.commit來提交一個mutation,

而實踐中,我們會經常用到 ES2015 的 參數解構 來簡化代碼(特別是我們需要調用 commit 很多次的時候),如下案例:

actions: {
  increment ({ commit }) {
    commit('increment')
  }
}
//actions.js中
export default{
    //分發的時候有傳值的情況
	buyVip({commit},e){
		//mock api交互
		return new Promise((resolve,reject)=>{
			setTimeout(()=>{
				//修改本地state
				commit('setMemberInfo',{
					userStatus:e.userStatus,
					vipLevel:e.vipLevel
				})
				resolve('購買成功')

			},1000)
		})
		
	},
    //分發的時候無值,但需要使用state的情況
	getFreeVip({commit,state}){
		//mock api 交互
		return new Promise(function(resolve,reject) {
			setTimeout(function(){
				if(state.userStatus === 0){
					//僅限普通會員才能分享獲得高級會員資格
					commit('setMemberInfo',{
						userStatus:1,
						vipLevel:0
					});
					resolve('分享成功,您已獲得一個月的高級vip');
				}else{
					resolve('分享成功');
				}
			},1000)
		})
	}
}

 b)通過 dispatch 分發 action:

      store.dispatch可以處理被觸發的action函數返回的Promise,並且仍舊返回Promise,如下:

methods:{

    buy:function(e){
        //正常是與後臺交互,傳遞會員信息與購買繳費
        //此處是本地數據的處理
        //第一個參數是actions.js中的函數名
        //第二個參數是需要傳的值
        store.dispatch('buyVip',e).then(res=>{
            alert(res);
        })
    }
}

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章