vuex 的使用

用於多組件共享狀態,若是不打算開發大型單頁應用,使用 Vuex 多是繁瑣冗餘的。確實是如此——若是應用夠簡單,您最好不要使用 Vuex。可以使用簡單Bus總線的方式來管理共享的數據詳見(http://www.cnblogs.com/fanlinqiang/p/7756566.html)。可是,若是您須要構建是一箇中大型單頁應用,vuex能夠更好地在組件外部管理狀態html

引入:vue

src/store/index.jses6

import Vue from 'vue'
import Vuex from 'vuex'
import createLogger from 'vuex/dist/logger'

Vue.use(Vuex)


const store = new Vuex.Store({
      plugins: [createLogger()],
      state: {
        count: 0,
        todos: [
          { id: 1, text: '...', done: true },
          { id: 2, text: '...', done: false }
        ]
      },
      getters: {
        doneTodos: state => {
          return state.todos.filter(todo => todo.done)
        },
        doneTodosCount: (state, getters) => { //注:Getter 也能夠接受其餘 getter 做爲第二個參數
            return getters.doneTodos.length
        },
        getTodoById: (state) => (id) => { //getter 返回一個函數來實現給 getter 傳參
            return state.todos.find(todo => todo.id === id)
        }
      },
      mutations: { //mutation 必須同步執行,爲解決這個問題咱們引入了action
       increment (state, payload) { //store.commit 傳入額外的參數,即 mutation 的 載荷(payload)         
             state.count += payload.amount
          }
      },
      actions: {
        //Action 函數接受一個與 store 實例具備相同方法和屬性的 context 對象,
        //所以你能夠調用 context.commit 提交一個 mutation,或者經過 context.state 和 context.getters 來獲取 state 和 getters。
        increment (context) {
          context.commit('increment')
        },
        increment ({ commit }) { //es6解構
            commit('increment')
        },
        incrementAsync ({ commit }) {
            setTimeout(() => {
              commit('increment')
            }, 1000)
        },
        //store.dispatch 能夠處理被觸發的 action 的處理函數返回的 Promise,而且 store.dispatch 仍舊返回 Promise
        actionA ({ commit }) {
            return new Promise((resolve, reject) => {
              setTimeout(() => {
                commit('someMutation')
                resolve()
              }, 1000)
            })
          },
        actionB ({ dispatch, commit }) {
            return dispatch('actionA').then(() => {
              commit('someOtherMutation')
            })
          }
        // 假設 getData() 和 getOtherData() 返回的是 Promise
        async actionA ({ commit }) {
            commit('gotData', await getData())
          },
        async actionB ({ dispatch, commit }) {
            await dispatch('actionA') // 等待 actionA 完成
            commit('gotOtherData', await getOtherData())
         }
      }
})

export default store

最好提早在你的 store 中初始化好全部所需屬性。當須要在對象上添加新屬性時,你應該使用 Vue.set(obj, 'newProp', 123), 或者
以新對象替換老對象。例如,利用 stage-3 的對象展開運算符咱們能夠這樣寫:web

state.obj = { ...state.obj, newProp: 123 }

 組件a:vuex

import { mapState, mapActions, mapMutations } from 'vuex'

export default {
    data() {
        return {
      localCount: 2
    } }, methods:{ getTodoById(id) {
return this.$store.getters.getTodoById(id) }, increment(payload){ //payload能夠爲對象,如:{ amount: 10} this.$store.commit('increment', payload) //對象風格的提交方式 //this.$store.commit({type: 'increment',amount: 10}) }, ...mapMutations([ //mutation 都是同步事務,store.commit('increment'), 任何由 "increment" 致使的狀態變動都應該在此刻完成。 //爲解決異步問題咱們引入action 'increment', // 將 `this.increment()` 映射爲 `this.$store.commit('increment')` //add: 'increment' // 將 `this.add()` 映射爲 `this.$store.commit('increment')` // `mapMutations` 也支持載荷: 'incrementBy' // 將 `this.incrementBy(amount)` 映射爲 `this.$store.commit('incrementBy', amount)` ]), ...mapActions([ 'increment', // 將 `this.increment()` 映射爲 `this.$store.dispatch('increment')` //add: 'increment' // 將 `this.add()` 映射爲 `this.$store.dispatch('increment')` // `mapActions` 也支持載荷: 'incrementBy' // 將 `this.incrementBy(amount)` 映射爲 `this.$store.dispatch('incrementBy', amount)` ]), actionA() { store.dispatch('actionA').then(() => { // ... }) } }, computed:{ //count () { // return this.$store.state.count //} ...mapState({ // 使用對象展開運算符將此對象混入到外部對象中 // 箭頭函數可以使代碼更簡練 count: state => state.count, // 傳字符串參數 'count' 等同於 `state => state.count` countAlias: 'count', // 爲了可以使用 `this` 獲取局部狀態,必須使用常規函數 countPlusLocalState (state) { return state.count + this.localCount } }), doneTodosCount () { return this.$store.state.todos.filter(todo => todo.done).length }, DoneTodos(){ return this.$store.getters.doneTodos }, getDoneTodosCount () { return this.$store.getters.doneTodosCount }, // 使用對象展開運算符將 getter 混入 computed 對象中 ...mapGetters([ 'doneTodosCount', //映射 `this.doneCount` 爲 `store.getters.doneTodosCount` doneCount: 'doneTodosCount' ]) } }

 

main.jsapi

import Vue from 'vue'
import store from './store/'

new Vue({
  store
}).$mount('#app')

 

使用常量替代 Mutation 事件類型

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

// mutation-types.js
export const SOME_MUTATION = 'SOME_MUTATION'
// store.js
import Vuex from 'vuex'
import { SOME_MUTATION } from './mutation-types'

const store = new Vuex.Store({
  state: { ... },
  mutations: {
    // 咱們可使用 ES2015 風格的計算屬性命名功能來使用一個常量做爲函數名
    [SOME_MUTATION] (state) {
      // mutate state
    }
  }
})

 

Mutation 必須是同步函數app

一條重要的原則就是要記住 mutation 必須是同步函數。爲何?請參考下面的例子:異步

mutations: {
  someMutation (state) {
    api.callAsyncMethod(() => {
      state.count++
    })
  }
}

 

如今想象,咱們正在 debug 一個 app 而且觀察 devtool 中的 mutation 日誌。每一條 mutation 被記錄,devtools 都須要捕捉到前一狀態和後一狀態的快照。然而,在上面的例子中 mutation 中的異步函數中的回調讓這不可能完成:由於當 mutation 觸發的時候,回調函數尚未被調用,devtools 不知道何時回調函數實際上被調用——實質上任何在回調函數中進行的的狀態的改變都是不可追蹤的。async

Vuex 並不限制你的代碼結構。可是,它規定了一些須要遵照的規則:

  1. 應用層級的狀態應該集中到單個 store 對象中。

  2. 提交 mutation 是更改狀態的惟一方法,而且這個過程是同步的。

  3. 異步邏輯都應該封裝到 action 裏面。

只要你遵照以上規則,如何組織代碼隨你便。若是你的 store 文件太大,只需將 action、mutation 和 getter 分割到單獨的文件。

對於大型應用,咱們會但願把 Vuex 相關代碼分割到模塊中。下面是項目結構示例:

├── index.html
├── main.js
├── api
│   └── ... # 抽取出API請求
├── components
│   ├── App.vue
│   └── ...
└── store
    ├── index.js          # 咱們組裝模塊並導出 store 的地方
    ├── actions.js        # 根級別的 action
    ├── mutations.js      # 根級別的 mutation
    └── modules
        ├── cart.js       # 購物車模塊
        └── products.js   # 產品模塊

 modules:

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 的狀態

 爲何使用getters來訪問數據?

訪問state中數據直接使用this.$store.state.elements是能夠的,但根據業務的需求每每還要作一些業務上的處理,如:state中goods存放的是用戶購買的清單,但此時咱們只須要商品的數量,咱們不須要拿到全部的物品清單,此時咱們就能夠在得到state的過程當中在加上一層邏輯,也就是getters來得到物品數量

 vuex存取的數據,在刷新頁面時丟失?

 將數據存入cookie,webstorage,當刷新頁面時判斷是否有數據,沒有再去取

相關文章
相關標籤/搜索