vue 3 的 watch 默认不直接暴露新旧值,但可通过回调函数的第二个参数(适用于 ref/reactive 层属性)或手动缓存旧值(配合 deep 监听和 json/structuredclone)获取;watcheffect 的 oninvalidate 则适合副作用清理场景。

Vue 3 的 watch 默认不直接暴露新旧值,但通过合理写法完全可以拿到——关键在于「使用回调函数的第二个参数」和「手动缓存旧值」两种方式,适用于简单监听或深度比对等不同场景。
基础 watch:用回调参数直接获取新旧值(仅适用于 ref / reactive 的顶层属性)
当监听的是一个 ref 或 reactive 对象的**单个顶层响应式变量**时,watch 回调接收两个参数:新值(newValue)和旧值(oldValue),前提是开启 immediate: false(默认)且首次触发不执行(否则 oldValue 是 undefined)。
示例:
const count = ref(0)
watch(count, (newVal, oldVal) => {
console.log('count 变了:', oldVal, '→', newVal)
}, { immediate: false }) // 首次不触发,确保 oldVal 有值
⚠️ 注意:如果设置了 immediate: true,首次执行时 oldVal 为 undefined,需自行判断。
监听 reactive 对象或深层属性:必须用 getter 函数 + 缓存旧值
监听 reactive 对象、数组或嵌套字段(如 user.profile.name)时,watch 回调的第二个参数不再自动提供有效旧值(尤其在对象引用未变但内部变化时)。此时推荐「手动缓存 + 深度比对」方案:

