$onAction 是 Pinia 的 AOP 式 action 拦截机制,支持 before/after/onError 钩子,用于统一注入日志、Loading、错误处理等副作用,仅作用于 actions 方法而非 $patch 等 state 操作。

$onAction 是 Pinia 提供的面向切面(AOP)式监听机制,不是简单“监听动作调用”,而是能深入到 action 执行前、执行后、出错时的每个关键节点。它不修改业务逻辑,却能统一注入日志、错误处理、性能统计、Loading 状态等副作用。
核心用法:订阅一个 store 的所有 actions
调用 store.$onAction(callback) 即可为该 store 的每个 action 注册拦截器。回调函数接收一个上下文对象,含以下关键字段:
- name:正在执行的 action 名称(字符串)
- store:当前 store 实例
- args:调用时传入的参数数组
- after:成功完成后的钩子(自动等待 Promise resolve)
- onError:执行失败时的钩子(捕获同步 throw 或异步 reject)
注意:$onAction 不监听 $patch、$reset 等直接操作 state 的行为,只作用于定义在 actions 里的方法。
实战场景一:统一记录执行耗时与结果
在 action 开始时记下时间,在 after 或 onError 中计算并打印耗时:
const unsubscribe = userStore.$onAction(({ name, args, after, onError }) => {const start = Date.now()
console.log(`【开始】${name}(${args.join(', ')})`)
after(result => {
console.log(`【成功】${name} 耗时 ${Date.now() - start}ms,返回:`, result)
})
onError(error => {
console.warn(`【失败】${name} 耗时 ${Date.now() - start}ms,错误:`, error)
})
})
实战场景二:全局 Loading 状态联动
配合 ref 管理 loading 状态,让 UI 自动响应任意 action 的执行中状态:
import { ref } from 'vue'const globalLoading = ref(false)
userStore.$onAction(({ name, after, onError }) => {
if (name !== 'login') return // 可按需过滤
globalLoading.value = true
after(() => { globalLoading.value = false })
onError(() => { globalLoading.value = false })
})
组件中只需绑定 v-loading="globalLoading" 或类似逻辑即可。
实战场景三:错误重试 + 分类处理
对特定 action(如 fetchList)实现自动重试,并区分网络错误与业务错误:
userStore.$onAction(({ name, args, after, onError }) => {if (name === 'fetchList') {
let retryCount = 0
const maxRetry = 2
const retry = () => {
if (retryCount retryCount++
userStore.fetchList(...args).catch(retry)
} else {
console.error('请求失败,已重试', maxRetry, '次')
}
}
onError(err => {
if (err?.response?.status === 0) {
// 网络异常,触发重试
retry()
} else {
// 业务错误,直接上报
reportBizError(err)
}
})
}
})










