7.1 核心概念
- Pinia 插件
- 一个接收
context的函数,通过pinia.use(plugin)注册,对每个 store 生效一次。 - context
- 插件参数,含
store、options、pinia、app,可读取 store 定义并扩展它。 - $subscribe
- 订阅某个 store 的 state 变化,回调收到 mutation 描述与最新 state。
- $onAction
- 拦截 action 调用,可在 before/after/onError 三个时机插入逻辑(如日志、埋点)。
- 持久化(Persistence)
- 把 store state 写入 localStorage/sessionStorage,刷新页面后自动恢复。
- persistedstate 插件
- 社区事实标准
pinia-plugin-persistedstate,一行配置实现持久化。
7.2 编写一个插件
插件本质是往每个 store 上"挂东西"。最简单的插件给所有 store 加一个只读属性:
// plugins/hello.ts
import { PiniaPluginContext } from "pinia";
export function helloPlugin({ store }: PiniaPluginContext) {
// 给每个 store 注入 createdAt
store.createdAt = new Date();
// 返回的对象会合并进 store(会被 DevTools 追踪)
return { secret: "the cake is a lie" };
}
// main.ts 注册
const pinia = createPinia();
pinia.use(helloPlugin);
app.use(pinia);
插件能做什么
注入全局属性(如 router、i18n)、给所有 store 添加公共 action、包裹 action 记日志、实现持久化——凡是"对每个 store 都想做的事"都适合写成插件。
7.3 给 TypeScript 声明插件注入的属性
// 扩展类型,让 store.createdAt 有类型提示
import "pinia";
declare module "pinia" {
export interface PiniaCustomProperties {
createdAt: Date;
secret: string;
}
}
7.4 使用官方持久化插件
$ npm i pinia-plugin-persistedstate
// main.ts
import { createPinia } from "pinia";
import piniaPluginPersistedstate from "pinia-plugin-persistedstate";
const pinia = createPinia();
pinia.use(piniaPluginPersistedstate);
app.use(pinia);
然后在需要持久化的 store 上开启 persist:
export const useAuthStore = defineStore("auth", {
state: () => ({ token: "", user: null as User | null }),
actions: { /* ... */ },
// 最简:整个 state 存入 localStorage,key 用 store id
persist: true,
});
精细化配置
persist: {
key: "my-auth", // 自定义存储 key
storage: sessionStorage, // 默认 localStorage
pick: ["token"], // 只持久化部分字段
},
| 选项 | 作用 | 默认 |
|---|---|---|
| key | 存储键名 | store id |
| storage | localStorage / sessionStorage | localStorage |
| pick | 只持久化指定字段 | 全部 state |
| omit | 排除指定字段 | 无 |
| serializer | 自定义序列化(如加密) | JSON |
别持久化敏感/大体积数据
token 等敏感信息存 localStorage 有 XSS 风险,考虑 httpOnly Cookie;大对象会拖慢每次写入。用 pick 精确控制持久化范围。
7.5 $subscribe 订阅 state 变化
const cart = useCartStore();
cart.$subscribe((mutation, state) => {
// mutation.type: 'direct' | 'patch object' | 'patch function'
console.log(mutation.type, mutation.storeId);
// 手动持久化示例
localStorage.setItem("cart", JSON.stringify(state));
}, { detached: false });
7.6 $onAction 拦截 action
cart.$onAction(({ name, args, after, onError }) => {
const start = Date.now();
console.log(`调用 action: ${name}`, args);
after((result) => {
console.log(`${name} 完成,耗时 ${Date.now() - start}ms`);
});
onError((err) => {
console.error(`${name} 出错`, err);
});
});
$onAction 用途
统一日志、性能监控、埋点上报、错误上报(Sentry)——不用改动每个 action,在插件里对所有 store 注册一次即可全局生效。
7.7 小结与下一步
- 插件 =
pinia.use(fn),对每个 store 生效,可注入属性、包裹逻辑。 pinia-plugin-persistedstate一行persist: true实现本地持久化,用pick/omit精控。$subscribe监听 state 变化,$onAction拦截 action 调用。- 下一章深入 TypeScript——类型推断、类型化 store 与最佳实践。