Explorar el Código

fix(watch): new property addition should trigger deep watcher with getter

close #12967
close #12972
Evan You hace 2 años
padre
commit
6d857f5bee
Se han modificado 2 ficheros con 37 adiciones y 2 borrados
  1. 6 2
      src/v3/apiWatch.ts
  2. 31 0
      test/unit/features/v3/apiWatch.spec.ts

+ 6 - 2
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)

+ 31 - 0
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)
+  })
 })