vuex從0到實踐

初始vuex

第一步:安裝vuex

  • 直接下載或cdn連接

    <script src="/path/to/vue.js"></script>
    <script src="/path/to/vuex.js"></script>
    
  • 通過腳手架直接安裝

    vue create projectName
    
  • 創建項目後通過 npm 安裝

    npm install vuex --save
    
  • 創建項目後使用 yarn 安裝

    yarn add vuex
    
  • 通過vuex項目自行構建

    git clone https://github.com/vuejs/vuex.git node_modules/vuex
    cd node_modules/vuex
    npm install
    npm run build
    

第二步:瞭解vuex是什麼

vuex 是 專門爲了vue應用程序開發的狀態管理模式

本質:集中式的存儲管理應用到的所有組件的狀態,並讓相應的狀態以可預測的形式發生變化

設計思想:

把項目中全部的組件共享狀態抽取出來,進行一個單例模式管理。

項目中的所有組件樹構成了一個巨大的視圖,無論組件在樹的哪個位置,都能夠獲取到共享狀態的值並觸發相對應的事件。

和定義一個全局變量的區別:

  1. vuex中存儲的狀態是響應式的,任何一個組件修改了狀態值,在其他組件中都會相應的得到高效更新。
  2. vuex中儲存的狀態值是不能夠直接修改的。只能夠通過提交mutation進行修改,即不能在組件中隨便定義一個函數對狀態值進行修改。所有能夠使狀態值發生變化的事件都是被定義在store中的。

第三步:開始使用vuex

1、計數器

計數器實例

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

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

獲取當前狀態的值

store.state.count; 

觸發事件變更

store.commit("increment");

2、在vue中注入vuex

通過在根實例中註冊 store 選項,該 store 實例會注入到根組件下的所有子組件中,且子組件能通過 this.$store 訪問到。

注入vuex

Vue.use(Vuex);
new vue({
	el:"#app",
	store,
})

在子組件中獲取vuex狀態值

this.$store.state.count

第四步:瞭解vuex的核心概念

State

state是什麼

state 是vuex中唯一的一個狀態樹,即單一樹,包含了項目中全部的應用層級的狀態。

state 在vuex中作爲唯一的狀態源而存在

在子組件中如何獲取狀態值

假設你已經通過以上方式將vuex注入到了vue中

this.$store.state.count

在子組件中應該如何展示狀態值

一般情況下,如果我們在子組件中使用狀態值,最簡單的方式是通過計算屬性返回需要的某個狀態,這樣如果狀態發生改變,計算屬性也會相應的發生改變。

學會使用mapState()輔助函數

在開發過程中,如果一個子組件需要使用到多個共享狀態值,爲了減少計算屬性的聲明,可以使用mapState輔助函數進行聲明。

import { mapState } from 'vuex'
  • 如果需要給計算屬性重新命名,則mapState接受一個對象

    const Counter = {
    	template:`<div>{{count}}</div>`,
    	computed:mapState({
    		myCount:'count'
    	})
    }
    
  • 如果計算屬性名和狀態值的名稱一致,則mapState可以接受一個數組

    const Counter = {
    	template:`<div>{{count}}</div>`,
    	computed:mapState([count])
    }
    
  • 如果除了狀態值外,該子組件還有其他的計算屬性,則推薦使用對象展開運算符

    const Counter = {
    	template:`<div>{{count}}</div>`,
    	computed:{
    		childData(){ return '計算屬性' },
    		...mapState({
    			//...
    		})
    	}
    }
    

Getter

getter 的使用背景

在多個子組件中,一個計算屬性值依賴相同的多個狀態,或需要對狀態進行相同的處理。類似於以下場景:

computed: {
  doneTodosCount () {
    return this.$store.state.todos.filter(todo => todo.done).length
  }
}

爲此,vuex支持getter屬性,也可以理解爲store中的計算屬性。當getter的依賴值發生改變時,getter就會發生改變。

如何在store中聲明一個計算屬性?

Getter 接受 state 作爲自己的第一個參數

const store = new Vuex.Store({
  state: {
   // ... 狀態值
  },
  getters: {
    doneTodos: state => {
      return state.todos.filter(todo => todo.done)
    }
  }
})

如果在Getter中會使用到其他的getter,Getter也支持接受 getter 本身作爲自己的第二個參數

const store = new Vuex.Store({
  state: {
   // ... 狀態值
  },
  getters: {
    doneTodoCount:state => {
         return state.todos.filter(todo => todo.done).length
    }
    doneTodos: ( state , getters ) => {
      return getters.doneTodoCount
    }
  }
})

如何在組件中使用聲明好的Getter?

通過屬性訪問:getter 在通過屬性訪問時是作爲 Vue 的響應式系統的一部分緩存其中的

computed:{
	doneTodoCount(){
		return this.$store.getters.doneTodoCount;
	}
}

通過方法調用:該方式的前提是,Getter返回的爲一個方法,使用方法調用結果不會作爲緩存,每次調用都會重新執行該方法。

const store = new Vuex.Store({
	getters:{
		getTodoId:( state ) => (id) => {
			return state.todos.find( todo => todo.id === id )
		}
	}
})
this.$store.getters.getTodoId(2)

同樣被支持的 mapGetters函數

同 mapState 函數一致,在同一個組件中如果需要獲取多個 Getter ,推薦使用 mapGetters 輔助函數,用法同 mapState

Mutation

什麼是Mutation

Mutation 是 vuex 更新狀態值唯一可行的地方。即在子組件中通過提交Mutation從而達到修改state的目的。

在store中的Mutation 更像是組件中的方法,它含有一個字符串的事件類型和一個回調函數。回調函數就是我們修改狀態值的地方。

如何聲明一個Mutation?

聲明方式 和 Getter 一致,並且同樣接受state作爲第一個參數

const store = {
	state:{
		//...
	},
	getters:{
		//...
	},
	mutations:{
		increment(state){
			state.account++;
		}
	}
}

如何在子組件中提交一個Mutation

this.$store.commit('increment')

如何提交一個帶有參數的Mutation

提交一個帶有參數的 Mutation,在vuex中被稱之爲提交載荷。Mutation接受第二個參數作爲額外的參數,一般來說,載荷(即第二個參數)爲一個對象,方便傳遞更多的數據,也方便代碼的閱讀及維護。

const store = {
	state:{
		//...
	},
	getters:{
		//...
	},
	mutations:{
		increment(state , payLoad){
			state.accout += payLoad.n;
		}
	}
}
this.$store.commit('increment',{
	n:10
})

使用Mutation時一定要注意的地方

  1. 需要遵守vue的響應規則

    (1) 建議在state中初始化好所有的默認值

    (2) 當需要在對象上更新屬性時,要遵守vue更新對象的原則

  2. Mutation必須是同步函數

同樣被支持的 mapMutations輔助函數

同 Getter 一樣,需要獲取多個Mutation時,建議使用 mapMutations輔助函數,支持傳入數組和對象

Action

Action的產生背景

Action的作用類似於Mutation , 但是又不同於Mutation。因爲在Mutation中只能執行同步操作,且是直接修改了state狀態值。

  • Action同樣可以修改狀態值,但是是通過提交Mutation從而達到修改狀態值的目的。
  • Mutation只能執行同步操作,而在Action中可以執行任意異步的操作。

如何註冊Action

Action 接受一個和store實例具有相同方法和屬性的context對象參數,可以直接調用commit方法

const store = {
	state:{
		//...
	},
    getters:{
        //...
    },
    mutations:{
        addCount(state){
            state.count++
        }
    },
    actions:{
        increment(context){
            context.commit('addCount');
        }
    }
}

在組件中觸發Action

const Count = {
	methods:{
		addCount(){
			this.$store.dispatch('increment');
		}
	}
}

同樣支持載荷的Action

Action支持接受額外的數據作爲第二個參數,即載荷數據

 actions:{
        increment(context , payLoad){
            context.commit('addCount' , payLoad);
        }
    }
const Count = {
	methods:{
		addCount(){
			this.$store.dispatch('increment'.{
				count:10
			});
		}
	}
}

一般什麼條件下會使用Action

當我們需要一些異步操作及提交多個Mutation時,我們可能會需要是要Action,尤其是異步操作。

以下爲官方購物車案例:

actions: {
  checkout ({ commit, state }, products) {
    // 把當前購物車的物品備份起來
    const savedCartItems = [...state.cart.added]
    // 發出結賬請求,然後樂觀地清空購物車
    commit(types.CHECKOUT_REQUEST)
    // 購物 API 接受一個成功回調和一個失敗回調
    shop.buyProducts(
      products,
      // 成功操作
      () => commit(types.CHECKOUT_SUCCESS),
      // 失敗操作
      () => commit(types.CHECKOUT_FAILURE, savedCartItems)
    )
  }
}

同同同樣被支持的mapActions輔助函數

import { mapActions } from 'vuex'

export default {
  methods: {
    ...mapActions([
      'increment', 
      'incrementBy' 
    ]),
    ...mapActions({
      add: 'increment' 
    })
  }
}

Module

產生背景

當我們使用單一的文件樹時,整個store文件就容易變得很龐大複雜。使用Module的目的就是爲了使store更加便於管理。

每個模塊有屬於自己的state、Setter、Mutation、Action等屬性,單獨的模塊也可以再向下分子模塊。

如何定義新的模塊

const moduleA = {
  state:{},
  setters:{},
  mutations:{},
  actions:{}
}
const moduleB = {
  state:{},
  setters:{},
  mutations:{},
  actions:{}
}
const store = new Vuex.Store({
  modules:{
    a:moduleA,
    b:moduleB
  }
})

如何在子模塊訪問根節點和局部狀態值

  • Mutation 和 Getter 訪問局部狀態

    Mutation 和 Getter 接受到的第一個參數 state 就是當前子模塊的局部狀態

  • Action 訪問局部狀態 和 根節點

    Action 接受 具有store 實例方法和屬性的 context 對象爲第一個參數,context對象中的state指當前子模塊的局部狀態,context對象中rootState獲取的是根節點中的state值

  • Getter 訪問根節點

    Getter中 第一個參數爲 當前子模塊的state值、第二個參數爲當前子模塊的Getter值,第三個參數爲根節點 rootState

更加具有複用性的命名空間

默認情況下,模塊內部的屬性都是註冊在全局狀態下的,方便在發生修改時直接觸發。但是爲了模塊的更加封閉性及可複用性,你可以通過添加 namespaced: true 的方式使其成爲帶命名空間的模塊。

如何在具有命名空間的模塊內訪問全局內容

  • 在Getter 和 Mutation 中使用全局狀態

    在一個子模塊中,Getter/Mutation 接受到的參數爲( 當前子模塊的state、當前子模塊的getters、根節點狀態rootState、根節點getters:rootGetters )

  • 在Action中使用全局狀態

    rootState 和 rootGetters 會通過context 暴露在子模塊中.

如何在子模塊中分發全局內容

在 commit 和 dispatch 中 將 { root:true } 設置爲第三個參數,例如在b模塊中派發A模塊中的action

dispatch('a/getCount', null, { root: true })

如何在組件中訪問子模塊的狀態及提交事件

在子組件中訪問子模塊的state狀態和Getter

const Count = {
	computed:{
		 count(){
		 		return this.$store.state.a.count;
		 }getTodos(){
       return this.$store.getters.a.todos;
     }
	}
}

在子組件中提交事件

const Count = {
	methods:{
    add(){
      this.$store.commit('a/add' ,{
        count:10
      } )
    }
  }
}

在模塊中使用輔助函數

在輔助函數中,可以將模塊的命名作爲第一個參數傳遞給函數,這樣在第二個函數中自動綁定該模塊。

第五步:購物車實例

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