$subscribe是Pinia监听状态变更最轻量、最推荐的方式,监听mutation提交而非响应式赋值,接收mutation(含type、storeId、payload)和state快照两个参数,支持埋点、过滤、聚合、防抖及插件化全局注册。

$subscribe 是 Pinia 提供的轻量级、推荐使用的状态变更监听机制,它不监听响应式属性的每一次赋值,而是监听 state 的“提交行为”——即 mutation 被 commit 的那一刻。这意味着它天然适配 action 执行、$patch 批量修改、直接赋值(如 store.count = 5)等所有合法变更方式,且与 Vue Devtools 深度协同。
监听基本写法与参数含义
调用 store.$subscribe(callback) 即可注册监听。回调函数接收两个关键参数:
-
mutation:描述本次变更的元信息,含 type(如
"direct"、"increment"或"patchObject")、storeId、payload(仅 $patch 传对象时有值); - state:当前 store 的完整状态快照(是引用,不可直接修改)。
例如:
counterStore.$subscribe((mutation, state) => {<br> console.log(`[${mutation.type}] ${counterStore.$id} → count: ${state.count}`);<br>});
区分变更来源,避免误触发
真实项目中需过滤非业务变更,比如跳过 Vue Devtools 的调试操作或初始化 hydration:
- 检查 mutation.type === 'devtools',直接 return;
- 对特定 action 命名约定(如
hydrateFromStorage),在回调中判断mutation.type === 'hydrateFromStorage'并忽略; - 避免监听
mutation.events,该字段为内部使用,打包后可能不存在,不可依赖。
控制执行时机与优化上报
通过 options.flush 可指定回调触发时机:
-
{ flush: 'sync' }:同步执行,适合立即做日志记录或防抖清空; -
{ flush: 'pre' }:DOM 更新前执行,适合读取旧 DOM 状态; -
{ flush: 'post' }:DOM 更新后执行(默认),适合操作新 DOM 或更新 ref。
高频变更(如表单输入)建议加简单防抖:
let timer;<br>store.$subscribe((m, s) => {<br> if (m.type === 'devtools') return;<br> clearTimeout(timer);<br> timer = setTimeout(() => report({ store: s.$id, keys: Object.keys(m.payload || {}) }), 200);<br>});
配合持久化或 UI 响应的典型场景
监听不是为了“看”,而是为了“做”。常见落地方式包括:
- 将 state 序列化存入 localStorage:
localStorage.setItem('cart', JSON.stringify(state)); - 响应主题切换并更新 CSS 变量或动态背景:
document.documentElement.style.setProperty('--primary-color', state.themeColor); - 驱动非响应式 UI 元素(如 iframe src、SVG 图标路径),用 ref 绑定后在回调中更新其值。


















