uni-app小程序开发-使用Pinia进行全局状态管理

与VueX对比

Pinia (发音为 /piːnjʌ/)支持 Vue 3 和 Vue 2 ,对 TypeScript 也有很完好的支持,与 Vuex 相比,Pinia 提供了一个更简单的 API,提供了 Composition-API 风格的 API,最重要的是,在与 TypeScript 一起使用时具有可靠的类型推断支持。

状态管理弃用了 vuex 而采用Pinia 的 5个重要条件:

  • Pinia 的 API 设计非常接近 Vuex 5 的提案。(作者是 Vue 核心团队成员)
  • 无需像 Vuex 4 自定义复杂的类型来支持 typescript,天生具备完美的类型推断。
  • 模块化设计,你引入的每一个 store 在打包时都可以自动拆分他们。
  • 无嵌套结构,但你可以在任意的 store 之间交叉组合使用。
  • Pinia 与 Vue devtools 挂钩,不会影响 Vue 3 开发体验。

Pinia API 与 Vuex ≤4 有很大不同,即:

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

有关如何将现有 Vuex ≤4 项目转换为使用 Pinia 的更详细说明,请参阅 从Vuex 迁移指南

状态树的结构

作用 Vue Component Vuex Pinia
数据管理 data state state
数据计算 computed getters getters
行为方法 methods mutations / actions actions

可以看到 Pinia 的结构和用途都和 Vuex 与 Component 非常相似,并且 Pinia 相对于 Vuex ,在行为方法部分去掉了 mutations (同步操作)和 actions (异步操作)的区分,更接近组件的结构,入门成本会更低一些。

uni-app中使用

https://uniapp.dcloud.net.cn/tutorial/vue3-pinia.html

注意

uni-app 内置了 Pinia 。Vue 2 项目暂不支持。

HBuilder X 已内置了 Pinia,无需手动安装。

项目结构

1
2
3
4
5
6
7
8
9
├── pages
├── static
└── stores
└── common.js
├── App.vue
├── main.js
├── manifest.json
├── pages.json
└── uni.scss

main.js 中编写以下代码:

1
2
3
4
5
6
7
8
9
10
11
12
import App from './App'
import { createSSRApp } from 'vue';
import * as Pinia from 'pinia';

export function createApp() {
const app = createSSRApp(App);
app.use(Pinia.createPinia());
return {
app,
Pinia, // 此处必须将 Pinia 返回
};
}

首先创建一个 Store:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
import {
defineStore
} from 'pinia';

export const useCommonStore = defineStore('common', {
state: () => {
return {
count: 0,
cityName: "郑州"
};
},
actions: {
increment() {
this.count++;
},
},
});

使用

1
2
3
4
5
6
7
8
9
10
11
12
13
14
import { useCommonStore } from '@/stores/common';
import { mapState, mapStores, mapActions } from 'pinia'
export default {
computed: {
// 允许访问 this.commonStore
...mapStores(useCommonStore),
// 允许读取 this.count 和 this.cityName
...mapState(useCommonStore, ['count', 'cityName']),
},
methods: {
// 允许读取 this.increment()
...mapActions(useCommonStore, ['increment']),
},
}

赋值

1
this.commonStore.cityName = '全国';