vuex入門

安裝&使用

npm install vuex --save
  • 1

經過Vue.use()來使用:vue

import Vue from 'vue' import Vuex from 'vuex' Vue.use(Vuex)
  • 1
  • 2
  • 3
  • 4

Vuex是什麼

Vuex是一個專爲vue.js應用程序開發的狀態管理模式。它集中儲存該應用的全部數據,統一保管。便於維護。python

核心概念


state

vuex使用單一狀態樹,也就是一個對象包含了整個應用的全部狀態,它做爲惟一的數據源。也就是說,每一個應用僅有一個store實例。vuex

在Vue組件中得到Vuex狀態npm

Vuex用過store選項,提供了一種機制,將數據從跟組件注入到每一個子組件中(須要調用Vue.use(Vuex)):數組

import store from './store' new Vue({ el: '#app', // 把 store 對象提供給 「store」 選項,這能夠把 store 的實例注入全部的子組件 store, template: '<App/>', components: { App } })
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9

經過在根實例中註冊store選項,該store實例會注入到根組件下的全部子組件中。且子組件能經過this.$store訪問到:bash

const Counter = {
  template: `<div>{{ count }}</div>`, //從 store 實例中讀取狀態最簡單的方法就是在計算屬性中返回某個狀態: computed: { count () { return this.$store.state.count } } }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9

mapState輔助函數app

當一個組件須要獲取多個狀態時,逐個聲明計算屬性會很麻煩,爲此咱們可使用mapState輔助函數幫咱們生成:異步

// 在單獨構建的版本中輔助函數爲 Vuex.mapState import { mapState } from 'vuex' export default { // ... computed: mapState({ /*三種不一樣的方式*/ // 箭頭函數可以使代碼更簡練 count: state => state.count, // 傳字符串參數 'count' 等同於 `state => state.count` countAlias: 'count', // 爲了可以使用 `this` 獲取局部狀態,必須使用常規函數 countPlusLocalState (state) { return state.count + this.localCount } }) }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17

上邊咱們給mapState傳了一個對象,若是咱們要生成的計算屬性名稱與state子節點名稱相同時,也能夠直接給mapState傳入一個字符串數組:函數

computed: mapState([
  // 映射 this.count 爲 store.state.count 'count' ])
  • 1
  • 2
  • 3
  • 4

對象展開運算符工具

mapState函數返回的是一個對象,可是一個組件中的計算屬性,不只有來自store的,還有它局部的。那麼如何混用呢?咱們使用對象展開運算符:

computed: {
  //localComputed 是組件的局部計算屬性
  localComputed () { /* ... */ }, // 使用對象展開運算符將此對象混入到外部對象中 ...mapState({ // ... }) }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8

組件仍保有局部狀態

上邊說了組件的局部狀態,也就是隻有這個組件本身須要用到的數據,好比模態框組件是否顯示的狀態,這個數據只對該組件自己有意義,因此不該該放入Vuex,做爲局部狀態,反而更利於維護。

Getters

有時候咱們須要從store中的state中派生出一些狀態,例如對列表進行過濾並計數:

computed: { doneTodosCount () { return this.$store.state.todos.filter(todo => todo.done).length } }
  • 1
  • 2
  • 3
  • 4
  • 5

但若是咱們要在多個組件中使用此屬性,難道要複製這個函數嗎?Vuex容許咱們在store中定義getters(能夠認爲是store的計算屬性)。getter接受state做爲第一個參數:

// 在'store/index.js'中 const store = new Vuex.Store({ state: { todos: [ { id: 1, text: '...', done: true }, { id: 2, text: '...', done: false } ] }, getters: { doneTodos: state => { return state.todos.filter(todo => todo.done) }, // getters也能夠接受其餘getters做爲第二個參數 doneTodosCount: (state, getters) => { return getters.doneTodos.length } } })
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18

getters會暴露爲store.getters對象:

store.getters.doneTodos // -> [{ id: 1, text: '...', done: true }]
  • 1

mapGetters輔助函數

mapGetters輔助函數僅僅是將store中的getters映射到局部計算屬性:

import { mapGetters } from 'vuex' export default { // ... computed: { // 使用對象展開運算符將 getters 混入 computed 對象中 ...mapGetters([ 'doneTodosCount', 'anotherGetter', // ... ]) //若是想給getter屬性領取一個名字,能夠對象形式: mapGetters({ // 映射 this.doneCount 爲 store.getters.doneTodosCount doneCount: 'doneTodosCount' }) } }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18

Mutations

更改Vuex的store中的狀態的惟一方法是提交mutation。Vuex的mutataions很是相似於事件:每一個mutation都有一個字符串的事件類型(type)和一個回調函數(handler)。這個回調函數就是咱們實際進行狀態更改的地方,他會接受state做爲第一個參數:

const store = new Vuex.Store({ state: { count: 1 }, mutations: { increment (state) { // 變動狀態 state.count++ } } })
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11

上邊註冊了一個類型爲increment的mutation:「當觸發一個類型爲increment的mutation時,調用此函數。」實際使用時:store.commit('increment')

提交載荷(Payload)

載荷其實就是要傳入vuex的數據對象啦。

你能夠向store.commit傳入額外的參數,即mutation的載荷(payload):

//註冊mutation mutations: { // 這裏的傳入的數據對象payload就是載荷 increment (state, payload) { state.count += payload.amount } } //調用mutation的handler store.commit('increment', { amount: 10 }) //還可使用對象風格來調用 store.commit({ type: 'increment', amount: 10 })
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17

Mutations需遵照Vuex的響應規則
既然Vuex的store中的狀態時響應式的,那麼當咱們變動狀態時,監視狀態的vue組件也會自動更新。因此一樣要遵照vue的響應式注意事項:

  1. 最好提早在store中初始化好全部屬性
  2. 當須要在對象上添加新屬性時:1.用Vue.set;2.用新對象替換老對象。

使用常量替代Mutation事件類型

使用常量替代 mutation 事件類型在各類 Flux 實現中是很常見的模式。這樣可使 linter 之類的工具發揮做用,同時把這些常量放在單獨的文件中可讓你的代碼合做者對整個 app 包含的 mutation 一目瞭然:

// mutation-types.js export const SOME_MUTATION = 'SOME_MUTATION' // store.js import Vuex from 'vuex' import * as types from './mutation-types' const store = new Vuex.Store({ state: { ... }, mutations: { // 咱們可使用 ES2015 風格的計算屬性命名功能來使用一個常量做爲函數名 [types.SOME_MUTATION] (state) { // mutate state } } })
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17

mutation必須是同步函數

一條重要的原則就是要記住 mutation 必須是同步函數

在組件中提交Mutations

你能夠在組件中使用this.store.commit('type')提交mutataion,或者使用mapMutations輔助函數將組件中的methods映射爲store.commit調用(須要在根節點注入store)。

import { mapMutations } from 'vuex' export default { // ... methods: { ...mapMutations([ 'increment' // 映射 this.increment() 爲 this.$store.commit('increment') ]), ...mapMutations({ add: 'increment' // 映射 this.add() 爲 this.$store.commit('increment') }) } }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13

Actions

Action相似於mutation,不一樣之處在於:

  • Action提交的是mutataion,而不是直接變動狀態。
  • Action能夠包含任意異步操做。

註冊一個簡單的Action:

const store = new Vuex.Store({ state: { count: 0 }, mutations: { increment (state) { state.count++ } }, actions: { increment (context) { context.commit('increment') } } })
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15

Action 函數接受一個與 store 實例具備相同方法和屬性的 context 對象,所以你能夠調用 context.commit 提交一個 mutation,或者經過 context.state 和 context.getters 來獲取 state 和 getters。當咱們在以後介紹到 Modules 時,你就知道 context 對象爲何不是 store 實例自己了。

解構:ES6容許按照必定模式,從數組和對象中提取值,對變量進行賦值。

//例如:賦值 var [a,b,c] = [1,2,3] //例如:交換變量 [x,y] = [y,x] //例如:函數參數解構: // function add([x, y]){ // return x + y; // } // add([1, 2]); // 3 //實踐中咱們經常使用到 參數解構 來簡化代碼,下邊 //的 { commit } 就用到了解構。 actions: { increment ({ commit }) { commit('increment') } }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17

這裏解構的對象是context對象,也就是說context <==> { commit },這樣寫就能夠用commit替代context.commit,簡化代碼。

分發Action

Action經過store.dispatch方法觸發:store.dispatch('increment')
Actions 支持一樣的載荷方式和對象方式進行分發:

// 以載荷形式分發
store.dispatch('incrementAsync', { amount: 10 })  // 以對象形式分發 store.dispatch({ type: 'incrementAsync', amount: 10 })
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10

咱們能夠在Action內部執行異步操做:

actions: { incrementAsync ({ commit }) { setTimeout(() => { commit('increment') }, 1000) } } 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8

在組件中分發Action

你在組件中使用 this.$store.dispatch('xxx') 分發 action,或者使用 mapActions 輔助函數將組件的 methods 映射爲 store.dispatch 調用(須要先在根節點注入 store):

import { mapActions } from 'vuex' export default { // ... methods: { ...mapActions([ 'increment' // 映射 this.increment() 爲 this.$store.dispatch('increment') ]), ...mapActions({ add: 'increment' // 映射 this.add() 爲 this.$store.dispatch('increment') }) } }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13

組合Action

Modules

使用單一狀態樹,致使應用的全部狀態集中到一個很大的對象。可是,當應用變得很大時,store 對象會變得臃腫不堪。

爲了解決以上問題,Vuex 容許咱們將 store 分割到模塊(module)。每一個模塊擁有本身的 state、mutation、action、getters、甚至是嵌套子模塊——從上至下進行相似的分割:

const moduleA = {
  state: { ... }, mutations: { ... }, actions: { ... }, getters: { ... } } const moduleB = { state: { ... }, mutations: { ... }, actions: { ... } } const store = new Vuex.Store({ modules: { a: moduleA, b: moduleB } }) store.state.a // -> moduleA 的狀態 store.state.b // -> moduleB 的狀態
相關文章
相關標籤/搜索