如果你已经做过任何大规模单页应用程序的严肃开发,你可能已经熟悉了国家管理的概念,特别是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的州管理!