Vuex 概述

Vuex 的组成

每一个 Vuex 应用都有一个巨大的 “视图”,这个视图的核心叫作 store(仓库)。store 基本上就是一个数据的容器,它包含着应用中大部分的状态,所有组件之间的状态改变都需要告诉 store,再由 store 负责分发到各个组件。

抽象一点来说,store 就像是一个全局对象,可简单地理解成 window 对象下的一个对象,组件之间的通信和状态改变都可以通过全局对象来调用,但是 store 和全局对象还是有一些本质区别的,并且也更加复杂。下面先来看看 store 由哪些部分组成,Vuex 中有默认的 5 种基本的对象:

  • state:存储状态,是一个对象,其中的每一个 key 就是一个状态。

  • getter:表示在数据获取之前的再次编译和处理,可以理解为 state 的计算属性。

  • mutation:修改状态,并且是同步的。

  • action:修改状态,可以是异步操作。

  • modulestore 分割后的模块,为了开发大型项目,可以让每一个模块拥有自己的 statemutationactiongetter,使得结构更加清晰,方便管理,但不是必须使用的。

上面这些对象之间的工作流程如图 6-2 所示。

image 2024 02 23 07 56 38 805
Figure 1. 图6-2 Vuex的工作流程

上面的流程图中虽然没有标出 store,但是可以看出,Vuex 是一个抽象的概念,而 store 是一个表现形式,是具体的对象,在代码中真正使用的是 store,这个对象要比一般的全局对象要复杂很多。另外,Vuex 和单纯的全局对象具体有以下两点不同:

  • Vuex 的状态存储是响应式的,所谓响应式,就是说当 Vue 组件从 store 中读取状态时,若 store 中的状态发生变化,则相应的组件也会得到高效更新。

  • 不能直接改变 store 中的状态。改变 store 中状态的唯一途径就是显式地提交(commit)mutation(这是 Vuex 官方推荐的用法)。这样可以方便地跟踪记录每一个状态的变化,并且实现一些工具,帮助开发者更加全面地管理应用。

安装 Vuex

与使用 Vue.js 一样,可以在 HTML 页面中通过 <script> 标签的方式导入 Vuex,前提是必须要先导入 Vue.js,如示例代码 6-2-1 所示。

示例代码 6-2-1 导入 Vuex
<script src="https://unpkg.com/vue@3.2.28/dist/vue.global.js"></script>
<script src="https://unpkg.com/vuex@4.0.0/dist/vuex.global.js"></script>

当然,可以将这个链接指向的 JavaScript 文件下载到本地计算机中,而后再从本地计算机中导入。

在使用 Vuex 开发大型项目时,推荐使用 npm 方式来安装 Vuex。npm 工具能很好地和诸如 WebpackBrowserify 等模块打包器配合使用。安装方法如示例代码 6-2-2 所示。

示例代码 6-2-2 使用 npm 安装 Vuex

npm install vuex@next

一个简单的store

在完成安装之后,下面来实际演示如何创建一个 store。创建过程直截了当,仅需要提供一个初始 state 对象和一些 mutation,如示例代码 6-2-3 所示。

示例代码 6-2-3 创建一个简单的 store
const store = Vuex.createStore({
    state: {
        count: 0
    },
    mutations: {
        increment (state) {
            state.count++
        }
    }
})
const app = Vue.createApp({})
app.use(store) // 可以在组件中通过this.$store调用
app.mount("#app")

在上面的代码中创建了一个简单的 store 实例,store 中的状态保存在 state 中,然后可以通过 store.commit('increment') 来触发 state 状态的变更,注意 commit 方法的参数就是在 store 中定义的 mutationskey 值,打印 console.log(store.state.count),可以看到打印出了 “1”。

需要注意的是,通过提交 mutation 的方式,而不是直接改变 store.state.count 创建 store,这是因为我们想要更明确地追踪到状态的变化。这个简单的约定能够让我们的意图更加明显,这样即使其他开发者在阅读代码时也能更容易地解读应用内部的状态改变。此外,这样也便于实现一些能记录每次状态改变和保存状态快照的调试工具,例如 Chrome 浏览器的 Vue DevTools。有了这些工具,可以实现如 “时间穿梭机” 般的调试体验。

通常情况下,如果在创建 store 时启用严格模式,那么就会绝对禁止采用直接修改 state 的方式,代码如下:

const store = createStore({
    ...
    strict: true
})

在严格模式下,无论何时发生了状态变更且不是由 mutation 引起的,都会抛出错误。这能保证所有的状态变更都能被 Chrome 浏览器的 Vue DevTools 工具跟踪到。

由于 store 中的状态是响应式的,因此在组件中获取 store 中的状态经常会用到计算属性,并在计算属性的方法中返回 store 里面的 state 值。触发变化也仅仅是在组件的 methods 中提交 mutation,使用起来简单便捷,代码如下:

...
computed: {
    info() {
        return this.$store.state.info
    }
},
methods:{
    changeInfo(){
        this.$store.commit('changeInfo')
    }
}
...

下一节将结合具体的 Vue 组件来使用 store,并分别说明 stategettersmutationactionmodule 的使用方法。