Skip to content

Vuex: Vue 的状态管理模式

重要提示: Pinia 现在是 Vue 官方推荐的状态管理库,它提供了更简洁、更符合组合式 API 风格的 API。本章介绍的 Vuex 是 Vue 2 和早期 Vue 3 项目中广泛使用的状态管理方案。了解 Vuex 的概念对于维护现有项目仍然很有帮助。

什么是“状态管理模式”?

在一个复杂的应用中,多个组件可能会共享同一份状态(数据)。例如,用户的登录信息、购物车中的商品等。如果多个组件都依赖于同一份状态,并且都需要去修改这份状态,那么数据流就会变得非常混乱和难以维护。

状态管理模式就是将共享的状态从组件中抽离出来,放入一个全局的、集中的“仓库”(Store) 中进行管理。这样,任何组件都可以从这个仓库中读取状态,或者触发一个动作来修改状态。

Vuex 就是一个专为 Vue.js 应用程序开发的状态管理模式库。它采用集中式存储管理应用的所有组件的状态,并以相应的规则保证状态以一种可预测的方式发生变化。

Vuex 核心概念

每个 Vuex 应用的核心就是 store(仓库)。一个 store 包含以下几个核心部分:

1. State

State 就是驱动应用的唯一数据源,可以理解为存储在 store 中的数据对象。

js
import { createStore } from 'vuex'

const store = createStore({
  state() {
    return {
      count: 0,
      user: null
    }
  }
})

在 Vue 组件中,可以通过 this.$store.state.count (在选项式 API 中) 或 store.state.count (在组合式 API 中) 来访问 state。

2. Getters

有时候我们需要从 store 中的 state 中派生出一些状态,例如对列表进行过滤并计算总数。这就是 Getters 的用处。你可以把 getters 理解为 store 的计算属性。

js
const store = createStore({
  state: {
    todos: [
      { id: 1, text: '...', done: true },
      { id: 2, text: '...', done: false }
    ]
  },
  getters: {
    doneTodos(state) {
      return state.todos.filter(todo => todo.done)
    },
    doneTodosCount(state, getters) {
      return getters.doneTodos.length
    }
  }
})

3. Mutations

更改 Vuex 的 store 中的状态的唯一方法是提交 mutation。Vuex 中的 mutation 非常类似于事件:每个 mutation 都有一个字符串的事件类型 (type) 和一个回调函数 (handler)。这个回调函数就是我们实际进行状态更改的地方,并且它会接受 state 作为第一个参数。

js
const store = createStore({
  state: {
    count: 1
  },
  mutations: {
    increment(state) {
      // 变更状态
      state.count++
    },
    incrementBy(state, payload) {
      state.count += payload.amount
    }
  }
})

// 在组件中提交 mutation
store.commit('increment')
store.commit('incrementBy', { amount: 10 })

重要:Mutation 必须是同步函数。为了确保状态变化的可追溯性,任何异步操作都不应该放在 mutation 中。

4. Actions

Action 类似于 mutation,不同在于:

  • Action 提交的是 mutation,而不是直接变更状态。
  • Action 可以包含任意异步操作。
js
const store = createStore({
  state: {
    count: 0
  },
  mutations: {
    increment(state) {
      state.count++
    }
  },
  actions: {
    incrementAsync({ commit }) {
      setTimeout(() => {
        commit('increment')
      }, 1000)
    }
  }
})

// 在组件中分发 action
store.dispatch('incrementAsync')

总结

Vuex 通过将共享状态集中管理,并强制使用 mutation 来修改状态,使得状态的变化过程变得清晰、可预测和可调试。虽然 Pinia 是新项目的首选,但理解 Vuex 的核心思想(State, Getters, Mutations, Actions)对于理解现代前端状态管理仍然至关重要。