Переглянути джерело

fix(reactivity): fix recursive sync watcher on computed edge case

close #12033
close #12037
Evan You 1 рік тому
батько
коміт
10ff159240

+ 20 - 0
packages/reactivity/__tests__/watch.spec.ts

@@ -4,6 +4,7 @@ import {
   WatchErrorCodes,
   type WatchOptions,
   type WatchScheduler,
+  computed,
   onWatcherCleanup,
   ref,
   watch,
@@ -209,4 +210,23 @@ describe('watch', () => {
     source.value++
     expect(dummy).toBe(1)
   })
+
+  // #12033
+  test('recursive sync watcher on computed', () => {
+    const r = ref(0)
+    const c = computed(() => r.value)
+
+    watch(c, v => {
+      if (v > 1) {
+        r.value--
+      }
+    })
+
+    expect(r.value).toBe(0)
+    expect(c.value).toBe(0)
+
+    r.value = 10
+    expect(r.value).toBe(1)
+    expect(c.value).toBe(1)
+  })
 })

+ 8 - 3
packages/reactivity/src/effect.ts

@@ -260,11 +260,14 @@ export function endBatch(): void {
   let error: unknown
   while (batchedSub) {
     let e: Subscriber | undefined = batchedSub
-    batchedSub = undefined
+    let next: Subscriber | undefined
     while (e) {
-      const next: Subscriber | undefined = e.next
-      e.next = undefined
       e.flags &= ~EffectFlags.NOTIFIED
+      e = e.next
+    }
+    e = batchedSub
+    batchedSub = undefined
+    while (e) {
       if (e.flags & EffectFlags.ACTIVE) {
         try {
           // ACTIVE flag is effect-only
@@ -273,6 +276,8 @@ export function endBatch(): void {
           if (!error) error = err
         }
       }
+      next = e.next
+      e.next = undefined
       e = next
     }
   }