From 6d857f5bee275dc98106e3b2cbc7722f5ec0cfc0 Mon Sep 17 00:00:00 2001 From: Evan You Date: Thu, 7 Dec 2023 00:13:31 +0800 Subject: [PATCH] fix(watch): new property addition should trigger deep watcher with getter close #12967 close #12972 --- src/v3/apiWatch.ts | 8 +++++-- test/unit/features/v3/apiWatch.spec.ts | 31 ++++++++++++++++++++++++++ 2 files changed, 37 insertions(+), 2 deletions(-) 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) + }) })