Pinia 插件是可以同时使用多个的,而且它们是按顺序依次作用在每个 Store 上的。这种机制非常适合组合功能,比如同时使用持久化、日志追踪、权限守卫等插件,构建出一个高度自动化、具备横切能力的状态管理体系。
import { createPinia } from 'pinia'
import piniaPluginPersistedstate from 'pinia-plugin-persistedstate'
import piniaLogger from 'pinia-plugin-logger'
import { authGuardPlugin } from './plugins/authGuard'
import { apiPlugin } from './plugins/api'
const pinia = createPinia()
// 插件注册顺序决定执行顺序(按 use 添加顺序生效)
pinia.use(piniaPluginPersistedstate)
pinia.use(piniaLogger)
pinia.use(authGuardPlugin)
pinia.use(apiPlugin)
app.use(pinia)
defineStore()
│
└───> 插件1 处理 store(如注入 persist)
│
└───> 插件2 处理 store(如注入 logger)
│
└───> 插件3 ...
store
上的属性(如 $api
、$persist
)$onAction
/ $subscribe
监听,不会篡改 state 本身// plugins/api.ts
export const apiPlugin = ({ store }) => {
store.$api = axios.create({ baseURL: '/api' })
}
// plugins/logger.ts
export const loggerPlugin = ({ store }) => {
store.$onAction(({ name, args }) => {
console.log(`[Action]: ${name}`, args)
})
}
// plugins/authGuard.ts
export const authGuardPlugin = ({ store }) => {
if (store.$id === 'auth') {
store.$onAction(({ name, after }) => {
if (name === 'logout') {
console.warn('退出登录,清理本地缓存...')
}
})
}
}
全局注册:
pinia.use(apiPlugin)
pinia.use(loggerPlugin)
pinia.use(authGuardPlugin)
pinia.use(piniaPluginPersistedstate)
在 Store 中使用:
export const useUserStore = defineStore('user', {
state: () => ({ token: '', userInfo: null }),
actions: {
async login(data) {
const res = await this.$api.post('/login', data)
this.token = res.data.token
}
},
persist: true // 与持久化无缝结合
})
注意点 | 说明 |
---|---|
插件注册顺序影响执行顺序 | 如 logger 在 auth 之前,则先记录 action 再处理登出 |
不应在插件中同步修改状态 | 应通过 action 或订阅完成副作用逻辑 |
插件注入变量应使用 $ 前缀 |
避免与 state 属性冲突 |
SSR 场景需判断 process.client |
插件中涉及浏览器 API 时需处理 |
场景 | 推荐组合 |
---|---|
用户系统 | persistedstate + authGuard + logger |
表单缓存 | persistedstate (限路径) + logger |
多模块项目 | dynamicModulePlugin + apiPlugin + i18nPlugin |
SSR(Nuxt) | persistedstate (仅客户端启用) + 自定义 hydrationPlugin |
按需组合与定向应用 —— 这是大型项目中常见的“精细化状态管理优化”策略。
Pinia 插件机制本质上是作用于 每个 Store 实例初始化时,而不是全局一次性设置。因此,我们可以通过插件内部判断当前正在处理的 Store,再决定是否注入特定逻辑或功能。
// 插件本质结构
function myPlugin(context: PiniaPluginContext) {
const { store } = context
if (store.$id === 'auth') {
// 仅作用于 auth 模块
} else if (store.$id === 'settings') {
// 仅作用于 settings 模块
}
}
// plugins/customPlugin.ts
export function customPlugin({ store }) {
switch (store.$id) {
case 'auth':
store.$onAction(({ name }) => {
console.log(`[auth action]: ${name}`)
})
break
case 'settings':
store.$subscribe((mutation, state) => {
console.log(`[settings changed]: ${mutation.events}`, state)
})
break
default:
break
}
}
const pinia = createPinia()
pinia.use(customPlugin)
适用于多个插件对多个 store 进行组合控制。
// plugins/dispatcher.ts
import { pluginForAuth } from './plugin-auth'
import { pluginForSettings } from './plugin-settings'
const pluginMap = {
auth: pluginForAuth,
settings: pluginForSettings
}
export const pluginDispatcher = (ctx: PiniaPluginContext) => {
const plugin = pluginMap[ctx.store.$id]
if (plugin) {
plugin(ctx)
}
}
// plugin-auth.ts
export const pluginForAuth = ({ store }) => {
store.$onAction(({ name }) => {
console.log(`[Auth Action]: ${name}`)
})
}
// plugin-settings.ts
export const pluginForSettings = ({ store }) => {
store.$subscribe((mutation) => {
console.log(`[Settings Updated]:`, mutation)
})
}
// main.ts
pinia.use(pluginDispatcher)
✅ 这种方式非常适合大型系统中:
如果你希望 store 自身控制启用哪些插件逻辑,可以通过 state 或 meta 配置标记:
// 在 store 中配置
export const useUserStore = defineStore('user', {
state: () => ({
enableLogger: true
})
})
// 在插件中读取配置
if (store.enableLogger) {
store.$onAction(...)
}
方法 | 特点 |
---|---|
if (store.$id === 'xxx') 判断 |
最直接,可快速实现按 store 分支逻辑 |
插件调度器 pluginDispatcher |
模块化管理多插件逻辑,高度可维护 |
store 中定义 meta/config 控制 | 由 store 主动控制,支持动态开关插件功能 |