vuex使用中需要注意的點(diǎn)

vuex中幾個(gè)核心概念: state, getters, mutations, actions, module

getters

可以認(rèn)為是store的計(jì)算屬性;與計(jì)算屬性一樣,getter的返回值會(huì)根據(jù)它的依賴(lài)緩存起來(lái),且只有當(dāng)它的依賴(lài)值發(fā)生變化才會(huì)被重新計(jì)算


mapGetters

輔助函數(shù)僅僅是將 store 中的 getter 映射到局部計(jì)算屬性:

import { mapGetters } from 'vuex'

export default {
  // ...
  computed: {
  // 使用對(duì)象展開(kāi)運(yùn)算符將 getter 混入 computed 對(duì)象中
    ...mapGetters([
      'doneTodosCount',
      'anotherGetter',
      // ...
    ])
  }
}

mutations 只能是同步操作

更改vuex的store中的狀態(tài)的唯一方法就是提交 mutations
在 mutation 中混合異步調(diào)用會(huì)導(dǎo)致你的程序很難調(diào)試。例如,當(dāng)你能調(diào)用了兩個(gè)包含異步回調(diào)的 mutation 來(lái)改變狀態(tài),你怎么知道什么時(shí)候回調(diào)和哪個(gè)先回調(diào)呢?

mutation必須是同步函數(shù)

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

現(xiàn)在想象,我們正在 debug 一個(gè) app 并且觀(guān)察 devtool 中的 mutation 日志。每一條 mutation 被記錄,devtools 都需要捕捉到前一狀態(tài)和后一狀態(tài)的快照。然而,在上面的例子中 mutation 中的異步函數(shù)中的回調(diào)讓這不可能完成:因?yàn)楫?dāng) mutation 觸發(fā)的時(shí)候,回調(diào)函數(shù)還沒(méi)有被調(diào)用,devtools 不知道什么時(shí)候回調(diào)函數(shù)實(shí)際上被調(diào)用——實(shí)質(zhì)上任何在回調(diào)函數(shù)中進(jìn)行的狀態(tài)的改變都是不可追蹤的。


在組件中提交mutations

你可以在組件中使用 this.$store.commit('xxx') 提交 mutation,或者使用 mapMutations 輔助函數(shù)將組件中的 methods 映射為 store.commit 調(diào)用(需要在根節(jié)點(diǎn)注入 store)。

import { mapMutations } from 'vuex'

export default {
  // ...
  methods: {
    ...mapMutations([
      'increment', // 將 `this.increment()` 映射為 `this.$store.commit('increment')`

      // `mapMutations` 也支持載荷:
      'incrementBy' // 將 `this.incrementBy(amount)` 映射為 `this.$store.commit('incrementBy', amount)`
    ]),
    ...mapMutations({
      add: 'increment' // 將 `this.add()` 映射為 `this.$store.commit('increment')`
    })
  }
}

actions 可以是異步操作

  • action提交的是mutation,而不是直接更改狀態(tài)
  • action 可以包含任何異步操作

分發(fā) action

在組件中分發(fā)Action

你在組件中使用 this.$store.dispatch('xxx') 分發(fā) action,或者使用 mapActions 輔助函數(shù)將組件的 methods 映射為 store.dispatch 調(diào)用(需要先在根節(jié)點(diǎn)注入 store):

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

Action 通常是異步的,那么如何知道 action 什么時(shí)候結(jié)束呢?更重要的是,我們?nèi)绾尾拍芙M合多個(gè) action,以處理更加復(fù)雜的異步流程?

首先,你需要明白 store.dispatch 可以處理被觸發(fā)的 action 的處理函數(shù)返回的 Promise,并且 store.dispatch 仍舊返回 Promise:

// 假設(shè) getData() 和 getOtherData() 返回的是 Promise

actions: {
  async actionA ({ commit }) {
    commit('gotData', await getData())
  },
  async actionB ({ dispatch, commit }) {
    await dispatch('actionA') // 等待 actionA 完成
    commit('gotOtherData', await getOtherData())
  }
}

module

由于使用單一狀態(tài)樹(shù),應(yīng)用的所有狀態(tài)會(huì)集中到一個(gè)比較大的對(duì)象;當(dāng)應(yīng)用變得非常復(fù)雜時(shí),store 對(duì)象就有可能變得相當(dāng)臃腫。

為了解決以上問(wèn)題,Vuex 允許我們將 store 分割成模塊(module)。每個(gè)模塊擁有自己的 state、mutation、action、getter、甚至是嵌套子模塊——從上至下進(jìn)行同樣方式的分割:

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 的狀態(tài)
store.state.b // -> moduleB 的狀態(tài)

如果你希望使用全局 stategetter,rootStaterootGetter 會(huì)作為第三和第四參數(shù)傳入 getter,也會(huì)通過(guò) context 對(duì)象的屬性傳入 action。


命名空間

默認(rèn)情況下,模塊內(nèi)部的 action、mutation 和 getter 是注冊(cè)在全局命名空間的——這樣使得多個(gè)模塊能夠?qū)ν?mutation 或 action 作出響應(yīng)。

如果希望你的模塊具有更高的封裝度和復(fù)用性,你可以通過(guò)添加 namespaced: true 的方式使其成為命名空間模塊。當(dāng)模塊被注冊(cè)后,它的所有 getter、action 及 mutation 都會(huì)自動(dòng)根據(jù)模塊注冊(cè)的路徑調(diào)整命名。例如:

const store = new Vuex.Store({
  modules: {
    account: {
      namespaced: true,

      // 模塊內(nèi)容(module assets)
      state: { ... }, // 模塊內(nèi)的狀態(tài)已經(jīng)是嵌套的了,使用 `namespaced` 屬性不會(huì)對(duì)其產(chǎn)生影響
      getters: {
        isAdmin () { ... } // -> getters['account/isAdmin']
      },
      actions: {
        login () { ... } // -> dispatch('account/login')
      },
      mutations: {
        login () { ... } // -> commit('account/login')
      },

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

        // 進(jìn)一步嵌套命名空間
        posts: {
          namespaced: true,

          state: { ... },
          getters: {
            popular () { ... } // -> getters['account/posts/popular']
          }
        }
      }
    }
  }
})

如果你希望使用全局 state 和 getter,rootState 和 rootGetter 會(huì)作為第三和第四參數(shù)傳入 getter,也會(huì)通過(guò) context 對(duì)象的屬性傳入 action。
若需要在全局命名空間內(nèi)分發(fā) action 或提交 mutation,將 { root: true } 作為第三參數(shù)傳給 dispatch 或 commit 即可。


需要注意的點(diǎn)

1.默認(rèn)情況下,模塊內(nèi)的getter, mutation,action是注冊(cè)在全局空間的,state只注冊(cè)在局部命名空間的;

要想使模塊內(nèi)的getter, mutation,action注冊(cè)在模塊命名空間,必須在模塊內(nèi)加上 namespaced: true

未使用命名空間

使用命名空間

使用命名空間在調(diào)用action時(shí)必須使用

this.$store.dispatch('hero1/getHeroInfo');

computed: {
      doneTodosCount () {
          return this.$store.getters['hero1/doneTodos'][0].item;
      }
  },

參考鏈接

2.頁(yè)面刷新時(shí),store中的數(shù)據(jù)會(huì)清空

解決方案
https://stackoverflow.com/questions/43027499/vuex-state-on-page-refresh

3.雙向綁定(v-model)和 vuex 是否沖突

<template>
<div >
    <input type="text" v-model="obj.message">
</div>
</template>

<script>
export default {
    computed: {
        obj() {
            return this.$store.state.test.obj;
        },
    },
}
</script>

test.js

import Vue from 'vue';
const test = {
    state: {
        obj: {}
    },
    mutations: {
        updateMessage(state, message) {
            state.obj = { message };
        }
    },
}
export default test;

以上代碼在嚴(yán)格模式下會(huì)報(bào)錯(cuò)


vuexError

vuex開(kāi)啟嚴(yán)格模式, 僅需要在創(chuàng)建store的時(shí)候傳入 strict: true

const store = new Vuex.Store({
  // ...
  strict: true
})

在嚴(yán)格模式下, 無(wú)論何時(shí)發(fā)生了狀態(tài)變更且且不是由mutation函數(shù)引起的, 經(jīng)會(huì)拋出錯(cuò)誤, 這能保證所有的狀態(tài)變更都能被調(diào)試工具跟蹤到;

那我們應(yīng)該怎么處理呢, vuex的官方文檔中給給了解決方法: 表單處理

  1. 給 <input> 中綁定 value,然后偵聽(tīng) input 或者 change 事件,在事件回調(diào)中調(diào)用 action:
<template>
<div >
    <input type="text" :value="message" @input="updateMessage">
</div>
</template>

<script>
export default {
    computed: {
        message(){
            return this.$store.state.test.obj.message;
        },
    },
    methods: {
        updateMessage(e) {
            this.$store.commit('updateMessage', e.target.value)
        },
    }
}
</script>

  1. 雙向綁定的計(jì)算屬性: v-model + 使用帶有 setter 的雙向綁定計(jì)算屬性
<template>
<div >
    <input type="text" v-model="message">
</div>
</template>

<script>
export default {
    computed: {
        message: {
            get() {
                return this.$store.state.test.obj.message;
            },
            set(value) {
                this.$store.commit('updateMessage', value)
            }
        },
    },
}
</script>
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀(guān)點(diǎn),簡(jiǎn)書(shū)系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

  • 安裝 npm npm install vuex --save 在一個(gè)模塊化的打包系統(tǒng)中,您必須顯式地通過(guò)Vue.u...
    蕭玄辭閱讀 3,053評(píng)論 0 7
  • vuex 場(chǎng)景重現(xiàn):一個(gè)用戶(hù)在注冊(cè)頁(yè)面注冊(cè)了手機(jī)號(hào)碼,跳轉(zhuǎn)到登錄頁(yè)面也想拿到這個(gè)手機(jī)號(hào)碼,你可以通過(guò)vue的組件化...
    sunny519111閱讀 8,167評(píng)論 4 111
  • Vuex是什么? Vuex 是一個(gè)專(zhuān)為 Vue.js應(yīng)用程序開(kāi)發(fā)的狀態(tài)管理模式。它采用集中式存儲(chǔ)管理應(yīng)用的所有組件...
    蕭玄辭閱讀 3,242評(píng)論 0 6
  • vuex是一個(gè)狀態(tài)管理模式,通過(guò)用戶(hù)的actions觸發(fā)事件,然后通過(guò)mutations去更改數(shù)據(jù)(你也可以說(shuō)狀態(tài)...
    Ming_Hu閱讀 2,141評(píng)論 3 3
  • State 單一狀態(tài)樹(shù) Vuex 使用單一狀態(tài)樹(shù)——是的,用一個(gè)對(duì)象就包含了全部的應(yīng)用層級(jí)狀態(tài)。至此它便作為一個(gè)“...
    peng凱閱讀 745評(píng)論 2 0

友情鏈接更多精彩內(nèi)容