Pinia,下一代状态管理库?Vuex的替代品?

2022/01/30 Blog 共 2724 字,约 8 分钟

在十天前,尤大发布的一篇文章:“Vue 3 将在 2022 年 2 月 7 日成为新的默认版本”中提到,Pinia提供更简洁的状态管理。咦,Vuex 呢?Pinia 又是一个什么样的库?那让我们一探究竟吧~

惯例,先看一下 Pinia 的介绍。

Pinia 简介

在 2019 年 11 月左右,Pinia 最初是为 Composition API 风格的 Vue 的状态管理而生。发展至今,Pinia 是一个颇为成熟的 Vue 的状态管理库,它允许用户跨组件/页面共享状态,且在使用方式上,更加贴近 Vue3 的组合式 API 方式:

声明:export const useStore = defineStore('main',{xxx})

使用:const store = useStore()

截止到本文编写之时,Pinia(v2.0.11) 可以提供的功能:

  • 开发工具的支持
    • 跟踪 state 改变、 action 的 Timeline,
    • 在组件中查看 store
    • 更加容易的调试 Timeline
  • 热更新
    • 在不重载页面时,变更 store,
    • 在开发时保持任何现有的状态
  • 插件功能,可以更自由的扩展 Pinia 功能,
  • 对 TypeScript 更加友好的支持
  • 服务器端渲染支持

Pinia VS Vuex

vite 搭一个 vue3+ts 的 demo,简单的上手 Pinia 后,感觉 Pinia 作为新的 Vue 全家桶成员,那种流畅感很强。那么相比 Vuex,它有什么区别呢?

Pinia 的作者(Eduardo)也是 Vue 核心成员之一,且也是参与 Vuex 的设计开发的,对于 Pinia,作者最初是探索下一代的 Vuex 是什么样的,结合 Vuex 5 核心团队讨论中的想法,发现 Pinia 已经实现了他们在 Vuex 5 中想要的大部分内容,因此决定实现 Pinia。

与 Vuex 相比,Pinia 提供了更简单的 API,也更加简洁,提供了组合式风格的 API,最重要的是,它对 TypeScript 的支持,是 Vuex <= 4 无法比拟的。在未来,Pinia 不断发展中,可能还会融入 Vuex 中,但那已经是 Vuex 5 及之后了。

来自官方的对比:Pinia API 与 Vuex <=4 的不同:

  • 没有 mutations。mutations 被认为是非常冗长的。
  • 无需创建自定义复杂包装器来支持 TypeScript,所有内容都是类型化的,并且 API 的设计方式尽可能利用 TS 类型推断。
  • 不再需要注入魔法字符串、导入函数、调用它们,享受自动完成功能!
  • 无需动态添加 store,默认情况下它们都是动态的,您甚至不会注意到。请注意,您仍然可以随时手动使用 store 来注册它,但因为它是自动的,所以您无需担心。
  • 不再有模块的嵌套结构。您仍然可以通过在另一个 store 中导入和使用 store 来隐式嵌套 store,但 Pinia 通过设计提供扁平结构,同时仍然支持 store 之间的交叉组合方式。您甚至可以拥有 store 的循环依赖关系。
  • 没有命名空间模块。鉴于 store 的扁平架构,命名空间 store 是其定义方式所固有的,您可以说所有 store 都是命名空间的。

Pinia 初探

安装

pnpm/yarn add pinia or npm install pinia.

使用

1. 在应用程序中注入 pinia 插件

import { createApp } from 'vue';
import { createPinia } from 'pinia';

createApp(xxx).use(createPinia());

对于搭配 Vue2 使用时,还需要安装 @vue/composition-api ,

import { createPinia, PiniaVuePlugin } from 'pinia';

Vue.use(PiniaVuePlugin);
const pinia = createPinia();

new Vue({
    el: '#app',
    // other options...
    // ...
    // note the same `pinia` instance can be used across multiple Vue apps on
    // the same page
    pinia,
});

2. 定义 store

如同一个变量、函数,在使用之前,需要先声明定义,在 Pinia 中 store 也是如此,通过defineStore定义一个 store,其中,’xxx’ 是 store 的唯一 ID,在 devtools 中也可以查看。另外,通常将返回的函数命名为 use… 是组合式风格的一个约定,而 useXxxStore 中的 Xxx 通常是该 store 所属的功能或者类。

import { defineStore } from 'pinia';

export const useXxxStore = defineStore('xxx', {});

3. 使用 store

实例化 store 后,就可以通过实例访问定义在 state、getter 中的属性,也可以调用 action 中的方法。

import { useXxxStore } from '@/stores/xxx';

export default {
    setup() {
        const xxx = useXxxStore();
        // use store
        // xxx.xxx
    },
};

关注点

  1. store 是一个用 reactive 包裹的对象,也就意味着,它不能解构,否则会失去其响应性,如cosnt { count } = counterStore,不过,可以使用 storeToRefs()进行解构。
  2. 由于这是一个组合式风格的状态代码,我们可以为不同的功能模块,用不同的文件定义 store,只需要在相应的功能模块引入即可。这对代码拆分和逻辑拆分都很有用。

Getters

Pinia 的 getters 与 Vuex 的 getter 区别不大,不过在访问时,Vuex 是store.getters.xxx,Pinia 不需要再多一层,则是store.xxx,如同 state。

Actions

action 相当于组件中的方法(methods),通过 actions 属性声明定义,与 Vuex 一样,action 也可以是异步的,对了,与 Vuex 不同的是,Pinia 取消了 mutation。个人感觉可能认为 mutation 和 action 有一定的重复吧。

展望 Pinia

  • 直观,像组件一样书写 store
  • TypeScript 带来的类型安全
  • Vue devtools 提供不错的开发体验
  • 模块化设计,构建多个 store 文件,对逻辑、代码拆分极有帮助
  • 插件功能,扩展性很好
  • 文件大小极小,约 1kb

最后 & 总结

Pinia 相比 Vuex 更加简单、简洁,还可以自由扩展

Pinia 更加符合直觉的状态管理方式,模块化的导入导出使得状态的来龙去脉更加清晰

再者,Pinia 可以理解是下一代的 Vuex,后面可能会融入到 Vuex 5 中呢,目前 Vue 3 已经将 Pinia 作为官方推荐状态管理库了,即便是在生产环境中,也是可以使用了。

文档信息

Search

    Table of Contents