在 Vue 里面的中央状态管理器,用于改变数据和获取数据。Vuex 还能追踪所作的改变。

像这种管理数据的方式有很多

  1. 传值的方式,父组件往子组件传值
  2. eventBus 的方式

这两种方式共同的缺点是随着项目数据越来越多,文件会越来越复杂,不容易维护
同时也不能同追踪是谁来引发状态的改变源头

这就是 Vuex 设计的初衷

State

状态、数据

在 Vuex 通过 Vue.use(Vuex) 和 Vue.store 的选项注入到每个子组件中后,子组件能通过 this.$store 访问到 store

  1. Vue.use(Vuex);
  2. export default new Vuex.Store({
  3. state: {
  4. count: 0
  5. }
  6. });
  1. const Counter = {
  2. template: `<div>{{ count }}</div>`,
  3. computed: {
  4. count () {
  5. return this.$store.state.count
  6. }
  7. }
  8. }

Getter

state 加工后的值,类似于Vue 中的 computed 计算属性的 get

  1. Vue.use(Vuex);
  2. export default new Vuex.Store({
  3. state: {
  4. count: 0
  5. },
  6. getters:{
  7. doubleCounter: (state, getters) => state.counter * 2
  8. }
  9. });
  1. const Counter = {
  2. template: `<div>{{ count }}</div>`,
  3. computed: {
  4. count () {
  5. return this.$store.getters.doubleCounter
  6. }
  7. }
  8. }

通过方法访问

可以通过让 getter 返回一个函数,来实现给 getter 传参。 store 里的数组进行查询时非常有用。

  1. getters: {
  2. // ...
  3. getTodoById: (state) => (id) => {
  4. return state.todos.find(todo => todo.id === id)
  5. }
  6. }
  7. store.getters.getTodoById(2) // -> { id: 2, text: '...', done: false }

getter 在通过方法访问时,每次都会去进行调用,而不会缓存结果。

Mutations

用于改变状态,
而且操作通过 Vue Devtools 是有记录跟踪到的,但正因如此 Mutations 也只能做同步的操作,这样才能记录到正确的跟踪信息

  1. Vue.use(Vuex);
  2. export default new Vuex.Store({
  3. state: {
  4. count: 0
  5. },
  6. getters:{
  7. doubleCounter: (state, getters) => state.counter * 2
  8. },
  9. mutations:{
  10. increment(state, payload) {
  11. state.count += payload
  12. }
  13. }
  14. });
  1. const Counter = {
  2. template: `<div>{{ count }}</div>`,
  3. computed: {
  4. count () {
  5. return this.$store.getters.doubleCounter
  6. }
  7. },
  8. methods: {
  9. increment(){
  10. this.$store.commit('increment', 1)
  11. }
  12. }
  13. }

Action

正因 Mutations 只能做同步的操作,但有些情况就是需要作异步的操作。这时就用于 Action
在 Mutations 上面加多一层,可以用于异步的 Action。当 Action 完成时,才提交 mutation 来改变状态。
所以 Action 类似于 mutation,不同在于:

  • Action 提交的是 mutation,而不是直接变更状态。
  • Action 可以包含任意异步操作。

Action 函数接受一个与 store 实例具有相同方法和属性的 context 对象
context.commit 提交一个 mutation
context.state / context.getters 获取 state / getters

  1. Vue.use(Vuex);
  2. export default new Vuex.Store({
  3. state: {
  4. count: 0
  5. },
  6. getters:{
  7. doubleCounter: (state, getters) => state.counter * 2
  8. },
  9. mutations:{
  10. increment(state, payload) {
  11. state.count += payload
  12. }
  13. },
  14. actions:{
  15. increment: (context, payload) => {
  16. context.commit('increment', payload)
  17. }
  18. }
  19. });

辅助函数

当一个组件需要获取多个状态时候,将这些状态都声明为计算属性会有些重复和冗余。

mapState

生成一个 state 为基础的 computed 对象,参数接收数组或对象

  1. import { mapState } from 'vuex';
  2. export default {
  3. computed: mapState(['count']),
  4. // 相当于
  5. computed: {
  6. count () {
  7. return this.$store.state.count
  8. }
  9. },
  10. computed: mapState({counter: 'count'}), // 这样的 computed 对象可以给别名
  11. computed: {
  12. // 使用 rest 运算符混入 computed 对象中
  13. ...mapGetters({count: 'count'}),
  14. // ... 这样就可以有其它 computed 对象属性了
  15. }
  16. }

mapGetters

生成一个 getters 为基础的 computed 对象,参数接收数组或对象

  1. import { mapGetters } from 'vuex';
  2. export default {
  3. computed: mapGetters(['doubleCounter']),
  4. // 相当于
  5. computed: {
  6. doubleCounter () {
  7. return this.$store.getters.doubleCounter
  8. }
  9. },
  10. computed: mapGetters({count: 'doubleCounter'}), // 这样的 computed 对象可以给别名
  11. computed: {
  12. // 使用 rest 运算符混入 computed 对象中
  13. ...mapGetters({count: 'doubleCounter'}),
  14. // ... 这样就可以有其它 computed 对象属性了
  15. }
  16. }

mapMutations

映射 methods

  1. import { mapMutations } from 'vuex'
  2. export default {
  3. // ...
  4. methods: {
  5. ...mapMutations([
  6. 'increment', // 将 `this.increment()` 映射为 `this.$store.commit('increment')`
  7. // `mapMutations` 也支持载荷:
  8. 'incrementBy' // 将 `this.incrementBy(amount)` 映射为 `this.$store.commit('incrementBy', amount)`
  9. ]),
  10. ...mapMutations({
  11. add: 'increment' // 将 `this.add()` 映射为 `this.$store.commit('increment')`
  12. })
  13. }
  14. }

mapActions

映射 methods

  1. import { mapActions } from 'vuex'
  2. export default {
  3. // ...
  4. methods: {
  5. ...mapActions([
  6. 'increment', // 将 `this.increment()` 映射为 `this.$store.dispatch('increment')`
  7. // `mapActions` 也支持载荷:
  8. 'incrementBy' // 将 `this.incrementBy(amount)` 映射为 `this.$store.dispatch('incrementBy', amount)`
  9. ]),
  10. ...mapActions({
  11. add: 'increment' // 将 `this.add()` 映射为 `this.$store.dispatch('increment')`
  12. })
  13. }
  14. }

Module

将 store 分割成模块

  1. const moduleA = {
  2. state: { ... },
  3. mutations: { ... },
  4. actions: { ... },
  5. getters: { ... }
  6. }
  7. const moduleB = {
  8. state: { ... },
  9. mutations: { ... },
  10. actions: { ... }
  11. }
  12. const store = new Vuex.Store({
  13. modules: {
  14. a: moduleA,
  15. b: moduleB
  16. }
  17. })
  18. store.state.a // -> moduleA 的状态
  19. store.state.b // -> moduleB 的状态

命名空间

默认情况下,模块内部的 action、mutation 和 getter 是注册在全局命名空间的——这样使得多个模块能够对同一 mutation 或 action 作出响应

namespaced: true 使其成为带命名空间的模块