Просмотр исходного кода

fix(reactivity): onCleanup also needs to be cleaned (#8655)

close #5151
close #7695
花果山大圣 2 лет назад
Родитель
Сommit
73fd810eeb

+ 35 - 0
packages/runtime-core/__tests__/apiWatch.spec.ts

@@ -1205,4 +1205,39 @@ describe('api: watch', () => {
     expect(countWE).toBe(3)
     expect(countW).toBe(2)
   })
+
+  // #5151
+  test('OnCleanup also needs to be cleaned,', async () => {
+    const spy1 = vi.fn()
+    const spy2 = vi.fn()
+    const num = ref(0)
+
+    watch(num, (value, oldValue, onCleanup) => {
+      if (value > 1) {
+        return
+      }
+      spy1()
+      onCleanup(() => {
+        // OnCleanup also needs to be cleaned
+        spy2()
+      })
+    })
+
+    num.value++
+    await nextTick()
+    expect(spy1).toHaveBeenCalledTimes(1)
+    expect(spy2).toHaveBeenCalledTimes(0)
+
+    num.value++
+    await nextTick()
+
+    expect(spy1).toHaveBeenCalledTimes(1)
+    expect(spy2).toHaveBeenCalledTimes(1)
+
+    num.value++
+    await nextTick()
+    // would not be calld when value>1
+    expect(spy1).toHaveBeenCalledTimes(1)
+    expect(spy2).toHaveBeenCalledTimes(1)
+  })
 })

+ 2 - 1
packages/runtime-core/src/apiWatch.ts

@@ -273,10 +273,11 @@ function doWatch(
     getter = () => traverse(baseGetter())
   }
 
-  let cleanup: () => void
+  let cleanup: (() => void) | undefined
   let onCleanup: OnCleanup = (fn: () => void) => {
     cleanup = effect.onStop = () => {
       callWithErrorHandling(fn, instance, ErrorCodes.WATCH_CLEANUP)
+      cleanup = effect.onStop = undefined
     }
   }