掌握Vue.js中的状态管理

掌握Vue.js中的状态管理

用于 JavaScript 的 Vue 框架在构建用户界面和单页面应用程序(SPA)方面很受欢迎。为确保您的大型应用程序以最佳状态运行,您需要牢牢掌握状态管理,即管理和集中多个组件中的应用程序反应数据(状态)的过程。

在 Vue 中,状态管理长期以来一直依赖于 Vuex,这是一个为应用程序的所有组件提供集中存储的库。然而,Vue 生态系统的最新进展催生了 Vuex 的后继者 Pinia。

Pinia 提供了一种更加轻量级、模块化和直观的管理方法。它与 Vue 的反应系统和 Composition API 无缝集成,使开发人员可以轻松地以可扩展和可维护的方式管理和访问共享状态。

设置场景:Pinia 与 Vuex

作为 Vue 应用程序状态管理的首选库,Vuex 为应用程序的所有组件提供了一个集中存储空间。然而,随着 Vue 的发展,Pinia 代表了一种更现代的解决方案。让我们探讨一下它与 Vuex 的不同之处。

  • 应用程序接口(API)的不同 – 与 Vuex 相比,Pinia 的组成应用程序接口(Composition API)提供了更基本、更直观的应用程序接口,使管理应用程序状态变得更简单。此外,它的结构与大多数 Vue 开发人员所熟悉的 Vue 选项 API 非常相似。
  • 类型支持 – 一直以来,许多 Vue 开发人员都在为 Vuex 有限的类型支持而苦恼。相比之下,Pinia 是一个完全类型化的状态管理库,消除了这些顾虑。它的类型安全性有助于防止潜在的运行时错误,提高代码的可读性,并促进更流畅的扩展能力。
  • 反应性系统 – 两个库都利用了 Vue 的反应性系统,但 Pinia 的方法与 Vue 3 的 Composition API 更为接近。虽然反应性 API 功能强大,但在大型应用程序中管理复杂的状态可能具有挑战性。幸运的是,Pinia 简单而灵活的架构减轻了 Vue 3 应用程序中状态管理的麻烦。Pinia 的存储模式可让您定义一个存储空间,用于管理应用程序状态的特定部分,简化其组织并在组件间共享。
  • 轻量级特性 – Pinia 只有 1 KB,可无缝集成到您的开发环境中,其轻量级特性可提高您的应用程序性能和加载时间。

如何用 Pinia 创建 Vue 项目

要在 Vue 项目中集成 Pinia,请使用 Vue CLI 或 Vite 初始化项目。项目初始化后,可以通过 npm 或 yarn 将 Pinia 作为依赖关系安装。

  1. 使用 Vue CLI 或 Vite 创建一个新的 Vue 项目。然后,按照提示设置项目。
    // Using Vue CLI
    vue create my-vue-ap
    // Using Vite
    npm create vite@latest my-vue-app -- --template vue
  2. 将目录更改为新创建的项目文件夹:
    cd my-vue-app
  3. 将 Pinia 作为依赖项安装到您的项目中。
    // Using npm
    npm install pinia
    // Using yarn
    yarn add pinia
  4. 在主入口文件(通常是 main.jsmain.ts)中,导入 Pinia 并告诉 Vue 使用它:
    import { createApp } from 'vue';
    import { createPinia } from 'pinia';
    import App from './App.vue';
    const app = createApp(App);
    app.use(createPinia());
    app.mount('#app');

    在 Vue 项目中安装并设置好 Pinia 后,就可以定义并使用存储来进行状态管理了。

如何在 Pinia 中创建 Pinia

Store 是 Pinia 驱动的 Vue 应用程序中状态管理的支柱。它可以帮助您以协调一致的方式管理应用程序范围内的数据。存储是您定义、存储和管理应用程序各组件间共享数据的地方。

这种集中化非常重要,因为它可以构建和组织应用程序的状态变化,使数据流更可预测,调试更简单。

此外,Pinia 中的存储不仅仅是保存状态: Pinia 附带的功能可让您通过操作更新状态,并通过获取器计算派生状态。这些内置功能有助于提高代码库的效率和可维护性。

下面的示例说明了如何在项目的 src/store.js 文件中创建一个基本的 Pinia store。

import { defineStore } from 'pinia';
export const useStore = defineStore('main', {
state: () => ({
count: 0,
}),
actions: {
increment() {
this.count++;
},
},
getters: {
doubleCount: (state) => state.count * 2,
},
});

如何访问组件中的存储状态

与 Vuex 相比,Pinia 的状态访问和管理方法更加直观,尤其是如果您熟悉 Vue 3 的 Composition API。该 API 是一组能够在组件中包含反应性和可组合逻辑的 API。

请看下面的代码。

<template>
<div>{{ store.count }}</div>
</template>
<script>>
import { useStore } from './store';
export default {
setup() {
const store = useStore();
return { store };
},
}
</script>

在上述代码段中, <template> 标签包含了组件定义的 HTML 标记。要显示 Pinia store 中的 count 属性值,需要使用 Vue 的数据绑定语法,即 {{ count }}

useStore 函数提供了对 Pinia store 的访问,因此您可以使用 import { useStore } 从 store.js 中 import { useStore } from './store';

作为 Vue 3 的 Composition API 的一项功能,setup 函数定义了组件的反应状态和逻辑。然后在该函数中调用 useStore() 访问 Pinia store。

接着,const count = store.count 访问存储的 count 属性,使其在组件中可用。

最后,setup 返回 count,允许模板对其进行渲染。Vue 的反应性系统意味着,只要 store 中的 count 发生变化,组件的模板就会更新其值。

下面是输出的截图。

加载 Pinia store 演示模板

在浏览器中加载 Pinia store 演示模板的截图。

此示例说明了 Pinia 的优势:

  • 简单 – Pinia 允许直接访问 store 的状态,无需映射函数。相比之下,Vuex 需要 mapState (或类似的助手)才能实现相同的访问。
  • 直接访问存储 – Pinia 可让您直接访问状态属性(如 store.count),从而使您的代码更易读、更易懂。与此同时,Vuex 通常需要 getter 来访问即使是基本的属性,从而增加了复杂性,降低了可读性。
  • Composition API 兼容性 – 正如设置方法所展示的,Pinia 与 Composition API 的集成与现代 Vue 开发特别吻合,提供了更加统一的编码体验。

如何使用 Pinia 修改状态

在 Pinia 中,您可以使用动作来修改 store 的状态,这比 Vuex 的突变更灵活。请看下面的函数调用,它会增加状态的 count 属性:

store.increment(); // Increments the count

另一方面,Vuex 的等价方法除了定义至少一个动作外,还需要定义一个突变:

mutations: {
increment(state) {
state.count++;
},
},
actions: {
increment({ commit }) {
commit('increment');
},
}

Pinia 操作及其对应的 Vuex 代码体现了这两个库代码复杂度之间的重要差异。让我们进一步探讨这些差异:

  • 直接状态突变与间接状态突变 – 正如 increment 操作所展示的,Pinia 操作会直接改变存储的状态。在 Vuex 中,您只能使用突变来改变状态,而突变必须通过操作提交。这种流程分离确保了状态更改的可追踪性,但它比类似的 Pinia 操作更加复杂和僵化。
  • 异步与同步操作 – Vuex 的突变始终是同步的,不能包含异步进程,而 Pinia 操作则可以包含同步和异步代码。因此,您可以直接在动作中执行 API 调用或其他异步操作,从而使代码库更精简、更简洁。
  • 简化语法 – Vuex 通常需要定义突变并调用操作来提交它们。Pinia 则不需要这样。在操作中突变状态的功能减少了模板代码,使现有代码更加简洁明了。在 Vuex 中,基本的状态更新需要定义一个动作和一个突变,即使该动作只是提交突变。

从 Vuex 到 Pinia 的过渡

过渡到 Pinia 可以在简单性、灵活性和可维护性方面带来诸多好处,但需要仔细规划和考虑,以确保成功实施。

在转换之前,请确保:

  1. 熟悉 Pinia 与 Vuex 架构、状态管理模式和 API 之间的差异。了解这些差异对于有效重构代码和充分利用 Pinia 的功能至关重要。分析并重构你的 Vuex 状态、操作、
  2. 突变和获取器,以适应 Pinia 的结构。请记住,在 Pinia 中,您可以将状态定义为函数。你可以直接用动作来改变状态,也可以更顺利地实现获取器。
    计划如何过渡 Vuex 存储模块。Pinia 使用模块的方式与 Vuex 不同,但您仍可将存储结构用于类似目的。
  3. 利用 Pinia 改进的 TypeScript 支持。如果您的项目使用了 TypeScript,请考虑使用 Pinia 增强的类型推断和键入功能,以获得更好的类型安全性和开发人员体验。
  4. 修改测试策略,以适应状态管理的变化。这一过程可能涉及更新单元测试和集成测试中模拟存储或操作的方式。
  5. 考虑过渡对项目结构和组织的影响。考虑命名约定以及跨组件导入和使用存储的方式等因素。
  6. 确保与其他库的兼容性。检查转换可能影响的任何必要更新或依赖关系变化。
  7. 评估任何性能变化。Pinia 通常比 Vuex 更轻量级,但在过渡期间和之后,请继续监控应用程序的性能,以确保没有任何问题。

将存储从 Vuex 转换到 Pinia 需要几个步骤,以适应两者结构和 API 的差异。请看前面的 Pinia store。

在 Vuex store.js 文件中,相同的存储显示如下。

import Vue from 'vue';
import Vuex from 'vuex';
Vue.use(Vuex);
export default new Vuex.Store({
state: {
count: 0,
},
mutations: {
increment(state) {
state.count++;
},
},
actions: {
increment(context) {
context.commit('increment');
},
},
getters: {
doubleCount(state) {
return state.count * 2;
},
},
});

与之前的 Pinia store 一样,这个 Vuex 示例包含一个 state 对象,其单一的 count 属性初始化为 0

getters 对象包含直接突变状态的方法,而动作对象的方法则提交增量突变。

然后,getters 对象包含 doubleCount 方法,该方法将 count 状态乘以 2 并返回结果。

正如这段代码所展示的,在 Pinia 中实现存储与 Vuex 有几个明显的不同之处:

  • 初始化 – Pinia 不需要 Vue.use()
  • 结构 – 在 Pinia 中,状态是一个返回对象的函数,因此可以更好地支持 TypeScript 和反应性。
  • 动作(Actions)– Pinia 中的动作是直接改变状态的方法,无需突变,从而简化了代码。
  • Getters – 与 Vuex 类似,Pinia 中的 Getters 定义在存储定义中,可以直接访问状态。

如何在组件中使用存储

使用 Vuex 时,您可以这样使用存储:

<template>
<div>{{ doubleCount }}</div>
<button @click="increment">Increment</button>
</template>
<script>
import { mapGetters, mapActions } from 'vuex';
export default {
computed: {
...mapGetters(['doubleCount']),
},
methods: {
...mapActions(['increment']),
},
};
</script>

对于 Pinia 来说,用法变成了:

<template>
<div>{{ store.doubleCount }}</div>
<button> @click="store.increment">Increment</button>
</template>
<script>>
import { useStore } from '/src/store';
export default {
setup() {
const store = useStore();
return {
store,
};
},
};
</script>

Pinia store 转换

Pinia store 转换。

本示例涵盖基本转换。对于更复杂的 Vuex store,尤其是使用模块的 store,转换将涉及更详细的重组,以与 Pinia 的架构保持一致。

如何部署 Vue 应用程序

在部署之前,请注册免费试用 Kinsta 的应用程序托管服务。您将在 Dockerfile 的帮助下部署应用程序。

在项目根目录下创建一个 Dockerfile,并粘贴以下内容:

FROM node:latest
WORKDIR /app
COPY package*.json ./
RUN npm install
COPY ./ .
CMD ["npm", "run", "start"]

这段代码指示 Kinsta 的 Docker 引擎安装 Node.js ( FROM node:late )、创建工作目录 ( WORKDIR /app )、从 package.json 文件中安装 node 模块 ( RUN npm install ),并设置 Vue 应用程序启动时将调用的启动 ( CMD ["npm", "run", "start" ])命令。COPY 命令会将指定的文件或目录复制到工作目录中。

然后,将代码推送到首选的 Git 提供商(Bitbucket、GitHub 或 GitLab)。软件仓库准备就绪后,请按照以下步骤将应用程序部署到 Kinsta:

  1. 登录或创建账户,查看 MyKinsta 面板。
  2. 使用 Git 提供商授权 Kinsta。
  3. 选择左侧边栏上的 Application,然后单击 “Add Application” 按钮。
  4. 在出现的模态中,选择要部署的版本库。如果有多个分支,可以选择所需的分支并为应用程序命名。
  5. 从可用的数据中心位置中选择一个。
  6. 选择你的构建环境,然后选择使用 Dockerfile 来设置容器映像
  7. 如果你的 Dockerfile 不在版本库的根目录中,请使用 Context 来指明其路径,然后单击 “Continue“。
  8. 你可以将 Start command 留空。Kinsta 会使用 npm start 启动应用程序。
  9. 选择最适合您应用程序的 pod 大小和实例数量,然后单击 “Continue“。
  10. 填写信用卡信息,然后单击 Create application

除了应用程序托管,您还可以选择将 Vue 应用程序作为静态网站部署到静态网站托管中。

小结

从 Vuex 到 Pinia 的过渡标志着 Vue 生态系统中状态管理的重大演进。Pinia 的简单性、改进的 TypeScript 支持以及与 Vue 3 的 Composition API 的一致性使其成为现代 Vue 应用程序的理想选择。

评论留言