初步學習Vuex

什麼是vuex

vuex是專門爲vue.js開發的狀態管理模式,它將全部組件的狀態集中的存儲在一塊兒,而且用相應的規則使這些狀態以一種可預測的方式發生改變。vue

vuex是作什麼用的

前面說到vuex是專門爲vue.js開發的狀態管理模式,那麼究竟什麼是「狀態管理模式」呢? 以我目前對狀態的理解就是組件在某個時刻呈現出的視圖、數據的狀態。在vue的項目開發中咱們常常會遇到多個組件共享某個狀態。即:多個視圖依賴同一組件 或者 不一樣視圖的行爲須要改變同一狀態。
對於這種狀況父子組件以前經過props進行傳參是很繁瑣的,同時兄弟組件是沒辦法作到的。而且不一樣視圖之間只能經過事件觸發或直接引用的方式傳遞數據。這顯然是很麻煩的。
所以就有了vuex,他將組件的全部狀態抽離出來,存儲在全局的一個倉庫裏,這樣無論組件在哪一個位置均可以獲取到狀態或者觸發行爲。vuex就像一個巨大的倉庫同樣能夠爲咱們存儲着全部組件的狀態和改變狀態的行爲,同時維持着視圖和狀態之間的獨立性,使得代碼變得結構更加清晰且易維護。vuex

vuex要如何使用

  • 首先安裝vuex

npm install vuex --savenpm

  • 引入vuex

import Vuex from 'vuex'
vue.use(Vuex)數組

  • 建立一個 store,僅須要提供一個初始 state 對象和一些 mutation:
const store = new Vuex.Store({
  state: {
    count: 0
  },
  mutations: {
    increment (state) {
      state.count++
    }
  }
})
複製代碼
  • 獲取狀態對象
// 建立一個 Counter 組件
const Counter = {
  template: `<div>{{ count }}</div>`,
  computed: {
    count () {
      return store.state.count
    }
  }
}
複製代碼

因爲 Vuex 的狀態存儲是響應式的,從 store 實例中讀取狀態最簡單的方法就是在計算屬性中返回某個狀態promise

  • 經過 store.commit 方法觸發狀態變動:
store.commit('increment')
複製代碼

注意:改變狀態的惟一方式就是經過commit提交mutationbash

  • mapState 輔助函數
    當組件獲取多個狀態時,爲了不因將狀態聲明爲計算屬性而是代碼重複冗餘,咱們可使用mapState輔助函數
//引入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
    }
  })
}
複製代碼

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

computed: mapState([
  // 映射 this.count 爲 store.state.count
  'count'
])
複製代碼
  • vuex中的Getter
    Getter至關於vuex中的計算屬性,是對一些狀態的操做(若是一些狀態的操做會被屢次使用不妨將他們寫入Getter中調用),當他所依賴的狀態發生改變的時候,Getter返回的值也會發生相應的變化。
//Getter 接受 state 做爲其第一個參數,接受其餘 getter 做爲第二個參數:
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)
    }
  }
})
複製代碼

經過屬性訪問Getter異步

store.getters.doneTodos // -> [{ id: 1, text: '...', done: true }]
複製代碼
  • mapGetters 輔助函數
    mapGetters 輔助函數僅僅是將 store 中的 getter 映射到局部計算屬性:
import { mapGetters } from 'vuex'

export default {
  // ...
  computed: {
  // 使用對象展開運算符將 getter 混入 computed 對象中
    ...mapGetters([
      'doneTodosCount',
      'anotherGetter',
      // ...
    ])
  }
}
複製代碼
  • Vuex 中的 mutation
    vuex中的mutation相似於事件,每一個mutation都由表明此事件的名稱(type)和回調函數兩部分組成,回調函數中就是進行狀態更改的地方,在大型項目中爲了使整個 app 包含的 mutation 一目瞭然,一般會使用常量替代 Mutation 事件類型,將這些常量單獨寫在一個.js文件中。 Mutation 必須是同步函數,若要進行異步操做能夠將其寫在action中
//它會接受 state 做爲第一個參數:
const store = new Vuex.Store({
  state: {
    count: 1
  },
  mutations: {
    increment (state) {
      // 變動狀態
      state.count++
    }
  }
})
複製代碼
  • 提交載荷(Payload)
    你能夠向 store.commit 傳入額外的參數,即 mutation 的 載荷(payload)大多數時候載荷是一個對象,這樣能夠包含多個字段而且記錄的 mutation 會更易讀:

兩種提交方式async

//方式一
store.commit('increment', {
  amount: 10
})
*******
mutations: {
  increment (state, payload) {
    state.count += payload.amount
  }
}
//方式二  ——對象風格的提交方式
mutations: {
  increment (state, payload) {
    state.count += payload.amount
  }
}
*******
store.commit({
  type: 'increment',
  amount: 10
})
複製代碼
  • vuex中的Action
    Action 相似於 mutation,不一樣在於:
  1. Action 提交的是 mutation,而不是直接變動狀態。
  2. Action 能夠包含任意異步操做。

註冊一個簡單的action函數

const store = new Vuex.Store({
  state: {
    count: 0
  },
  mutations: {
    increment (state) {
      state.count++
    }
  },
  //action接受一個和store有相同屬性和方法的context 對象
  //所以你能夠調用 context.commit 提交一個 mutation
  //經過 context.state 和 context.getters 來獲取 state 和 getters
  actions: {
    increment (context) {
      context.commit('increment')
    }
  }
})
複製代碼
  • 觸發Action
store.dispatch('increment')

// 以載荷形式分發
store.dispatch('incrementAsync', {
  amount: 10
})

// 以對象形式分發
store.dispatch({
  type: 'incrementAsync',
  amount: 10
})
複製代碼
  • 在組件中分發 Action
import { mapActions } from 'vuex'

export default {
  // ...
  methods: {
    ...mapActions([
      'increment', // 將 `this.increment()` 映射爲 `this.$store.dispatch('increment')`

      // `mapActions` 也支持載荷:
      'incrementBy' // 將 `this.incrementBy(amount)` 映射爲 `this.$store.dispatch('incrementBy', amount)`
    ]),
    ...mapActions({
      add: 'increment' // 將 `this.add()` 映射爲 `this.$store.dispatch('increment')`
    })
  }
}
複製代碼
  • 組合 Action
  • store.dispatch能夠處理action返回的promise,而且 store.dispatch 仍舊返回 Promise:
store.dispatch('actionA').then(() => {
  // 處理Action返回的promise
})
複製代碼
  • 使用async / await時,組合Action
// 假設 getData() 和 getOtherData() 返回的是 Promise

actions: {
  async actionA ({ commit }) {
    commit('gotData', await getData())
  },
  async actionB ({ dispatch, commit }) {
    await dispatch('actionA') // 等待 actionA 完成
    commit('gotOtherData', await getOtherData())
  }
}
複製代碼
  • vuex中的module
    若是將每一個組建的狀態,都放在同一個store中,那麼整個store會變得很臃腫,因此vuex提供了module這個屬性,使得每一個模塊擁有本身的 state、mutation、action、getter、甚至是嵌套子模塊
const moduleA = {
  state: { count: 0 },
  mutations: {
    increment (state) {
      // 這裏的 `state` 對象是模塊的局部狀態
      state.count++
    }
  },

  getters: {
    doubleCount (state) {
      return state.count * 2
    }
  }
}

const moduleB = {
  state: { ... },
  mutations: { ... },
  actions: { ... }
}

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

store.state.a // -> moduleA 的狀態
store.state.b // -> moduleB 的狀態
複製代碼
  • 命名空間
    若是但願你的模塊具備更高的封裝度和複用性,你能夠經過添加 namespaced: true 的方式使其成爲帶命名空間的模塊。當模塊被註冊後,它的全部 getter、action 及 mutation 都會自動根據模塊註冊的路徑調整命名。
const store = new Vuex.Store({
  modules: {
    account: {
      namespaced: true,

      // 模塊內容(module assets)
      state: { ... }, // 模塊內的狀態已是嵌套的了,使用 `namespaced` 屬性不會對其產生影響
      getters: {
        isAdmin () { ... } // -> getters['account/isAdmin']
      },
      actions: {
        login () { ... } // -> dispatch('account/login')
      },
      mutations: {
        login () { ... } // -> commit('account/login')
      },

      // 嵌套模塊
      modules: {
        // 繼承父模塊的命名空間
        myPage: {
          state: { ... },
          getters: {
            profile () { ... } // -> getters['account/profile']
          }
        },

        // 進一步嵌套命名空間
        posts: {
          namespaced: true,

          state: { ... },
          getters: {
            popular () { ... } // -> getters['account/posts/popular']
          }
        }
      }
    }
  }
})
複製代碼
相關文章
相關標籤/搜索