Vuex 入门 —— 使用 Vuex 来管理你的 Vue.js 应用状态

翻译 Summer ⋅ 于 1周前 ⋅ 139 阅读 ⋅ 原文地址
这是一篇协同翻译的文章,目前翻译进度为 58%,你可以点击『我来翻译』按钮来 参与翻译

file

如果你做过大型的单页应用,你对『状态管理』的概念肯定会很熟悉。尤其是你如果使用过 Facebook 的 Redux 架构 Redux。在这篇文章里,我将带你了解下如果在 Vue 中使用 Vuex 来实现类似的设计模式。

alex 翻译于 1周前

准备

按照

Vuex 虽然是 Vue 官方的包,但是其并没有内置。你需要自己决定 你的应用中是否会用到它,然后使用 Yarn 或者 NPM 进行安装。

# Yarn 的方式
$ yarn add vuex
# NPM 的方式
$ npm install vuex --save

接下来在你的应用初始化代码那,开启 Vuex 插件:

main.js

import Vue from 'vue';
import Vuex from 'vuex';
import App from 'App.vue';

Vue.use(Vuex);

new Vue({
  el: '#app',
  render: h => h(App)
});
alex 翻译于 1周前

新建一个 Store

在开始之前,你需要创建一个 Vuex Store。Store 是一个全局的响应式对象,这遵循了 Vue 一般的响应式模式。它无法被直接读取或者修改,这样保证了状态的一致性,并且跟踪其状态改变也会变得相对简单。请见下面代码:

store.js

export const store = new Vuex.Store({
  state: {
    safelyStoredNumber: 0
  }
});
alex 翻译于 1周前

现在你可以在你所有的模块中通过 import 来导入,或者你可以将其注入 Vue 的全局根对象以此在所有模块中都可以通过 this.$store 直接读取到。在接下来的其余文章里,我们都将统一使用第二种方法。

main.js

import Vue from 'vue';
import Vuex from 'vuex';
import App from 'App.vue';
import { store } from './store.js';

Vue.use(Vuex);

new Vue({
  store,
  el: '#app',
  render: h => h(App)
});
alex 翻译于 1周前

访问状态

现在的 Store 不能做任何事情。它是一个独立的状态盒子,用于防止你的行为被意外的读取和操作,要从 Store 读取数据,你需要创建一个Getter。

使用 Getters

Getters 仅仅是存储在一个函数中的状态,它接收一个状态对象并从组件中返回一个值。属性作为其计算属性,而不是函数。如果一个 Getter 需要一个参数,它可以返回一个带第二个参数的函数。
store.js

export const store = new Vuex.Store({
  state: {
    safelyStoredNumber: 0
  },
  getters: {
    safelyStoredNumber: state => state.safelyStoredNumber,
    storedNumberMatches(state) {
      return matchNumber => {
          return state.safelyStoredNumber === matchNumber;
      }
    }
    // 简写方法:
    // storedNumberMatches: state => matchNumber => state.safelyStoredNumbers === matchNumber
  }
});
weixia942 翻译于 1周前

然而,访问组件中的 getters 的简单方法是通过 Vuex 的 mapGettershelper 方法。 这使你可以将 getter 安装到组件中的顶级计算属性。

如果你想重命名组件中的 gettermapGetters 可以获取一个对象。

App.vue

<template>
  <p>The safely stored number: {{safelyStoredNumber}}<p>
</template>

<script>
import { mapGetters } from 'vuex'

export default {
  computed: {
    ...mapGetters([
      // 将 “safelyStoredNumber” getter 加载到组件的作用域。
      'safelyStoredNumber'
    ])
  }
}
</script>
Ellison 翻译于 1天前

Modifying State

Synchronous Mutations

Direct modification of state in Vuex is done by calling a function called a mutation. A mutation is passed the current state and an optional payload. The payload can be any object. Mutationsmust be synchronous and shouldn't return a value. They can be used directly by running this.$store.commit('mutationName', payload).

store.js

export const store = new Vuex.Store({
  state: {
    safelyStoredNumber: 0
  },
  ...
  mutations: {
    incrementStoredNumber(state) {
      state.safelyStoredNumber++;
    },
    setStoredNumber(state, newNumber) {
      // newNumber is the payload passed in.
      state.safelyStoredNumber = newNumber;
    }
  }
});

As with getters, Vuex has a convenience method for mutations in component as well, the mapMutations helper method. This allows you to mount mutations as methods in your component.

App.vue

<template>
  <p>The safely stored number: {{safelyStoredNumber}}<p>
</template>

<script>
import { mapMutations } from 'vuex'

export default {
  ...
  methods: {
    ...mapMutations([
      // Mounts the "incrementStoredNumber" mutation to `this.incrementStoredNumber()`.
      'incrementStoredNumber',
      // Mounts the "setStoredNumber" mutation to `this.setStoredNumber(newNumber)`.
      'setStoredNumber'
    ])
  }
}
</script>

Asynchronous Actions

In more complicated apps, it's likely that you will need to perform some asynchronous actions that modify the state. Vuex handles this with actions. They are defined on your state object as well, and are passed the entire state context, which allows them to access getters and commit mutations. They are expected (but not required) to return a promise indicating completion status. Using ES2017 async/await, you can write very terse but easy to understand async actions. Actions are used in components directly with this.$store.dispatch('actionName', payload).then(response => {}).

To modify state within an action, use context.commit('mutationName', payload). Multiple mutations are allowed inside an action.

store.js

import myRemoteService from './my-remote-service.js'

export const store = new Vuex.Store({
  state: {
    safelyStoredNumber: 0
  },
  ...
  actions: {
    async setNumberToRemoteValue(context) {
      // Commits the 'setStoredNumber' mutation with the value of whatever myRemoteService.getRemoteValue() resolves through a promise.
      context.commit('setStoredNumber', await myRemoteService.getRemoteValue());
      return Promise.resolve();
    },
  }
});

If you're not familiar with async / await, seriously, go read about it. It's awesome. The short of it is, it pauses the execution of the current function until the awaited promise resolves, allowing you to essentially use promise resolutions as variables without all the extra boilerplate normally needed.

The Vuex convenience method for actions, (predictably named mapActions) is used in the same way as the one for mutations.

App.vue

<template>
  <p>The safely stored number: {{safelyStoredNumber}}<p>
</template>

<script>
import { mapActions } from 'vuex'

export default {
  ...
  methods: {
    ...mapActions([
      // Mounts the "setNumberToRemoteValue" action to `this.setNumberToRemoteValue()`.
      'setNumberToRemoteValue',
    ])
  }
}
</script>

Modularizing

A single store is fine if you're only working with a small set of data, but inevitably at some point you'll want to split your constantly-growing list of actions, mutations, and getters into separate sections. Thankfully Vuex provides a system to do this as well. Modules. Despite the scary name, a module is simply a normal object with state, getters, mutations, and actionsproperties. You can easily create one by doing this:

my-store-module.js

export const myModule = {
  // This makes your getters, mutations, and actions accessed by, eg: 'myModule/myModularizedNumber' instead of mounting getters, mutations, and actions to the root namespace.
  namespaced: true,
  state: {
    myModularizedNumber: 0
  },
  getters: {
    myModularizedNumber: state => state.myModularizedNumber
  },
  mutations: {
    setModularizedNumber(state, newNumber) {
      state.myModularizedNumber = newNumber
    }
  }
}

store.js

import { myModule } from './my-store-module.js';

export const store = new Vuex.Store({
  modules: {
    myModule
  },
  state: {
    safelyStoredNumber: 0
  },
  ...
});

你可以按需将模块嵌套在模块中,另外,mapGetters,mapMutations,和 mapActions 都可以在第一个参数中传入一个命名空间,这样你就可以不必像下面这样写代码了:

...mapGetters([
  'myModule/nestedModule/subNestedModule/exampleGetter',
  'myModule/nestedModule/subNestedModule/anotherGetter',
])

你可以像这样传入参数:

...mapGetters('myModule/testedModule/subNestedModule', [
  'exampleGetter',
  'anotherGetter'
])

希望该文章能帮助你了解 Vuex 状态管理!

科大大 翻译于 1周前

原文地址:https://alligator.io/vuejs/intro-to-vuex

译文地址:https://vuejscaff.com/topics/95/introduc...


本文中的所有译文仅用于学习和交流目的,转载请务必注明文章译者、出处、和本文链接
我们的翻译工作遵照 CC 协议,如果我们的工作有侵犯到您的权益,请及时联系我们。

回复数量: 0
    暂无评论~~
    您需要登陆以后才能留下评论!

    Vue.js 官方中文文档

    前端开发环境部署