diff --git a/src/v3/apiWatch.ts b/src/v3/apiWatch.ts index 141a58eb686..7160009dabb 100644 --- a/src/v3/apiWatch.ts +++ b/src/v3/apiWatch.ts @@ -185,8 +185,11 @@ function doWatch( } const instance = currentInstance - const call = (fn: Function, type: string, args: any[] | null = null) => - invokeWithErrorHandling(fn, null, args, instance, type) + const call = (fn: Function, type: string, args: any[] | null = null) => { + const res = invokeWithErrorHandling(fn, null, args, instance, type) + if (deep && res && res.__ob__) res.__ob__.dep.depend() + return res + } let getter: () => any let forceTrigger = false @@ -209,6 +212,7 @@ function doWatch( if (isRef(s)) { return s.value } else if (isReactive(s)) { + s.__ob__.dep.depend() return traverse(s) } else if (isFunction(s)) { return call(s, WATCHER_GETTER) diff --git a/test/unit/features/v3/apiWatch.spec.ts b/test/unit/features/v3/apiWatch.spec.ts index c92bc150ae7..a684d16116e 100644 --- a/test/unit/features/v3/apiWatch.spec.ts +++ b/test/unit/features/v3/apiWatch.spec.ts @@ -1200,4 +1200,35 @@ describe('api: watch', () => { expect(parentSpy).toHaveBeenCalledTimes(1) expect(childSpy).toHaveBeenCalledTimes(1) }) + + // #12967 + test('trigger when adding new property with Vue.set (getter)', async () => { + const spy = vi.fn() + const r = reactive({ exist: 5 }) + watch(() => r, spy, { deep: true }) + set(r, 'add', 1) + + await nextTick() + expect(spy).toHaveBeenCalledTimes(1) + }) + + test('trigger when adding new property with Vue.set (getter in array source)', async () => { + const spy = vi.fn() + const r = reactive({ exist: 5 }) + watch([() => r], spy, { deep: true }) + set(r, 'add', 1) + + await nextTick() + expect(spy).toHaveBeenCalledTimes(1) + }) + + test('trigger when adding new property with Vue.set (reactive in array source)', async () => { + const spy = vi.fn() + const r = reactive({ exist: 5 }) + watch([r], spy, { deep: true }) + set(r, 'add', 1) + + await nextTick() + expect(spy).toHaveBeenCalledTimes(1) + }) })