pinia 状态管理

介绍

Pinia 是 Vue 的专属状态管理库,同时适用于 2he3,它允许你跨组件或页面共享状态。
可以搭配持久化插件一起使用,如:pinia-plugin-persistedstate

特点

  • 去除mutations,比较于 Vuex 更加简单
  • 状态管理更简单,更易用
  • 支持options apicomposition api
  • 全面的TypeScript支持
  • 轻量
  • 兼容性 服务端渲染支持

安装

1
pnpm install pinia

创建实例与引用

1
2
3
4
5
import { createApp } from "vue";
import pinia from "./stores";
import App from "./App.vue";

createApp(App).use(pinia).mount("#app");

使用

定义存储库./store,在文件夹下创建 index.ts 作为总导出文件,再创建 modules 文件夹,创建对应的模块文件,如user.ts

定义模块

1
2
3
4
5
6
7
8
9
10
11
12
# index.ts
import { createPinia } from 'pinia'
import persist from 'pinia-plugin-persistedstate'
// 创建 pinia 实例
const pinia = createPinia()
// 使用持久化存储插件
pinia.use(persist)

// 默认导出,给 main.ts 使用
export default pinia
// 模块统一导出
export * from './modules/user'
1
2
3
4
5
6
7
8
9
10
11
12
13
14
# 定义示例一
import { defineStore } from "pinia";
# counter是唯一的模块标识符,不能重复
export const useCounterStore = defineStore("counter", {
state: () => ({ count: 0, name: "Eduardo" }),
getters: {
doubleCount: (state) => state.count * 2,
},
actions: {
increment() {
this.count++;
},
},
});
1
2
3
4
5
6
7
8
9
10
11
12
13
14
# 定义示例二
export const useCounterStore = defineStore('counter', () => {
# state
const count = ref(0)
const name = ref('Eduardo')
# action
const doubleCount = computed(() => count.value * 2)
# getter
function increment() {
count.value++
}

return { count, name, doubleCount, increment }
})

在组件中使用

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
<script setup>
import { useCounterStore } from '@/stores/counter'
import { computed } from 'vue'

const store = useCounterStore()
// 解构之后会失去响应式
const { name, doubleCount } = store
// name 将会一直是 "Eduardo"
// doubleCount 将会一直是 0
setTimeout(() => {
store.increment()
}, 1000)
// ✅ 而这一部分代码就会维持响应式
// 💡 在这里你也可以直接使用 `store.doubleCount`
const doubleValue = computed(() => store.doubleCount)
</script>

可以使用 storeToRefs 保持响应式

1
2
3
4
5
import { useCounterStore } from "@/stores/counter";
import { storeToRefs } from "pinia";
const store = useCounterStore();
const { name, doubleCount } = storeToRefs(store);
# 在Option API中 需要使用辅助函数 mapState

数据重置

1
2
3
4
5
6
7
8
# $reset()将store重置为初始状态
import { useCounterStore } from "@/stores/counter";

const counterStore = useCounterStore();

function resetData() {
counterStore.$reset();
}

插件

由于有了底层 API 的支持,Pinia store 完全支持各类扩展。
插件是通过 pinia.use() 添加到 pinia 实例的。最简单的例子是通过返回一个对象将一个静态属性添加到所有 store。

1
pinia.use(() => ({ hello: "world" }));
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
import { createPinia } from "pinia";

// 创建的每个 store 中都会添加一个名为 `secret` 的属性。
// 在安装此插件后,插件可以保存在不同的文件中
function SecretPiniaPlugin() {
return { secret: "the cake is a lie" };
}

const pinia = createPinia();
// 将该插件交给 Pinia
pinia.use(SecretPiniaPlugin);

// 在另一个文件中
const store = useStore();
store.secret; // 'the cake is a lie'

<<< more >>>

其他:
zustand(nextjs)
vuex(vue)
redux(react)