用 Vuex 管理 Vue.js 状态

如果你已经做过任何大规模单页应用程序的严肃开发,你可能已经熟悉了国家管理的概念,特别是Facebook通过Redux普及的Flux架构。

准备

安装

Vuex虽然是Vue的官方包,但没有内置,您必须决定是否需要它在您的应用程序中,然后通过线或npm相应安装。

1# Yarn
2$ yarn add vuex
3# NPM
4$ npm install vuex --save

然后,在您的应用程序 bootstrap 中,请确保您启用Vuex插件。

 1[label main.js]
 2import Vue from 'vue';
 3import Vuex from 'vuex';
 4import App from 'App.vue';
 5
 6Vue.use(Vuex);
 7
 8new Vue({
 9  el: '#app',
10  render: h => h(App)
11});

创建一个商店

要利用Vuex提供的功能,您首先需要创建一个商店。 商店基本上是一个遵循正常Vue反应模式的全球反应对象。 它无法直接访问或修改,以确保一致的状态,并允许轻松跟踪变化。

1[label store.js]
2export const store = new Vuex.Store({
3  state: {
4    safelyStoredNumber: 0
5  }
6});

现在,要访问商店,您要么必须将其导入到您的所有组件中,要么可以将其注入到 root 视图实例中,以便自动将其注入到您的应用程序中的每个其他组件中。

 1[label main.js]
 2import Vue from 'vue';
 3import Vuex from 'vuex';
 4import App from 'App.vue';
 5import { store } from './store.js';
 6
 7Vue.use(Vuex);
 8
 9new Vue({
10  store,
11  el: '#app',
12  render: h => h(App)
13});

入境国家

现在你真的不能用商店做任何事情. 这是一个孤立的黑匣子为你的状态,防止任何意想不到的行动读取或操纵它。

使用Getters

在您的组件中,它可以通过 this.$store.getters.property 作为计算属性访问,而不是作为一个函数。

 1[label store.js]
 2export const store = new Vuex.Store({
 3  state: {
 4    safelyStoredNumber: 0
 5  },
 6  getters: {
 7    safelyStoredNumber: state => state.safelyStoredNumber,
 8    storedNumberMatches(state) {
 9      return matchNumber => {
10          return state.safelyStoredNumber === matchNumber;
11      }
12    }
13    // Shorthand:
14    // storedNumberMatches: state => matchNumber => state.safelyStoredNumbers === matchNumber
15  }
16});

然而,在您的组件中访问 getters 的最简单方法是通过 Vuex 的 mapGetters 辅助方法,这允许您将 getters 安装到您的组件中的顶级计算属性。

<$>[注意] mapGetters 可以使用一个对象,如果您希望在组件中更名为 getters。

 1[label App.vue]
 2<template>
 3  <p>The safely stored number: {{safelyStoredNumber}}<p>
 4</template>
 5
 6<script>
 7import { mapGetters } from 'vuex'
 8
 9export default {
10  computed: {
11    ...mapGetters([
12      // Mounts the "safelyStoredNumber" getter to the scope of your component.
13      'safelyStoredNumber'
14    ])
15  }
16}
17</script>

改变国家

同步突变

直接修改 Vuex 中的状态是通过调用一个称为突变的函数进行的。 突变是通过当前状态和可选的负载。 负载可以是任何对象。 突变必须是同步的,不应该返回一个值。 它们可以直接通过运行 this.$store.commit('mutationName', payload)来使用。

 1[label store.js]
 2export const store = new Vuex.Store({
 3  state: {
 4    safelyStoredNumber: 0
 5  },
 6  ...
 7  mutations: {
 8    incrementStoredNumber(state) {
 9      state.safelyStoredNumber++;
10    },
11    setStoredNumber(state, newNumber) {
12      // newNumber is the payload passed in.
13      state.safelyStoredNumber = newNumber;
14    }
15  }
16});

与 getters 一样,Vuex 还具有用于组件中的突变的便利方法,即Mutations 辅助方法,这允许您将突变作为组件中的方法。

 1[label App.vue]
 2<template>
 3  <p>The safely stored number: {{safelyStoredNumber}}<p>
 4</template>
 5
 6<script>
 7import { mapMutations } from 'vuex'
 8
 9export default {
10  ...
11  methods: {
12    ...mapMutations([
13      // Mounts the "incrementStoredNumber" mutation to `this.incrementStoredNumber()`.
14      'incrementStoredNumber',
15      // Mounts the "setStoredNumber" mutation to `this.setStoredNumber(newNumber)`.
16      'setStoredNumber'
17    ])
18  }
19}
20</script>

非同步行动

在更复杂的应用程序中,您可能需要执行一些改变状态的非同步操作. Vuex 处理这些操作. 它们也被定义为您的状态对象,并且通过了整个状态背景,允许他们访问 getters 并进行突变。 他们预计(但不需要)返回表示完成状态的承诺。 使用 ES2017 async/await,您可以写出非常简单但易于理解的 async 操作。 操作被直接使用在组件中. $store.dispatch('actionName', payload)。

若要更改操作中的状态,请使用 context.commit('mutationName', payload)。

 1[label store.js]
 2import myRemoteService from './my-remote-service.js'
 3
 4export const store = new Vuex.Store({
 5  state: {
 6    safelyStoredNumber: 0
 7  },
 8  ...
 9  actions: {
10    async setNumberToRemoteValue(context) {
11      // Commits the 'setStoredNumber' mutation with the value of whatever myRemoteService.getRemoteValue() resolves through a promise.
12      context.commit('setStoredNumber', await myRemoteService.getRemoteValue());
13      return Promise.resolve();
14    },
15  }
16});

<$>[注]如果你不熟悉async / wait,认真地阅读它. 它很棒. 它的缩短是,它暂停了当前函数的执行,直到预期的承诺得到解决,允许你基本上使用承诺分辨率作为变量,而无需正常需要的所有额外锅炉板。

Vuex 操作方便方法(可预测地图操作)以与突变方法相同的方式使用。

 1[label App.vue]
 2<template>
 3  <p>The safely stored number: {{safelyStoredNumber}}<p>
 4</template>
 5
 6<script>
 7import { mapActions } from 'vuex'
 8
 9export default {
10  ...
11  methods: {
12    ...mapActions([
13      // Mounts the "setNumberToRemoteValue" action to `this.setNumberToRemoteValue()`.
14      'setNumberToRemoteValue',
15    ])
16  }
17}
18</script>

模块化

一个单一的商店是好的,如果你只工作一个小数据集,但不可避免地在某个时候,你会想将你的不断增长的行动,突变和变异列表分成不同的部分。 幸运的是,Vuex提供了一个系统来这样做。 模块. 尽管可怕的名字,模块只是一个正常的对象,具有状态,变异,变异和行动属性。

 1[label my-store-module.js]
 2export const myModule = {
 3  // This makes your getters, mutations, and actions accessed by, eg: 'myModule/myModularizedNumber' instead of mounting getters, mutations, and actions to the root namespace.
 4  namespaced: true,
 5  state: {
 6    myModularizedNumber: 0
 7  },
 8  getters: {
 9    myModularizedNumber: state => state.myModularizedNumber
10  },
11  mutations: {
12    setModularizedNumber(state, newNumber) {
13      state.myModularizedNumber = newNumber
14    }
15  }
16}
 1[label store.js]
 2import { myModule } from './my-store-module.js';
 3
 4export const store = new Vuex.Store({
 5  modules: {
 6      myModule
 7  },
 8  state: {
 9    safelyStoredNumber: 0
10  },
11  ...
12});

此外,mapGetters、mapMutations 和 mapActions 都可以采用一个第一个参数,即一个模块名称空间,以防止您需要写代码:

1...mapGetters([
2  'myModule/nestedModule/subNestedModule/exampleGetter',
3  'myModule/nestedModule/subNestedModule/anotherGetter',
4])

相反,你可以这样写:

1...mapGetters('myModule/testedModule/subNestedModule', [
2  'exampleGetter',
3  'anotherGetter'
4])

希望这有助于为您清理Vuex的州管理!

Published At
Categories with 技术
Tagged with
comments powered by Disqus