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

fix(reactivity): prevent endless recursion in computed getters (#11797)

Jürg Lehni 1 год назад
Родитель
Сommit
716275d1b1
2 измененных файлов с 46 добавлено и 1 удалено
  1. 45 0
      packages/reactivity/__tests__/computed.spec.ts
  2. 1 1
      packages/reactivity/src/dep.ts

+ 45 - 0
packages/reactivity/__tests__/computed.spec.ts

@@ -1,4 +1,6 @@
 import {
+  type TestElement,
+  defineComponent,
   h,
   nextTick,
   nodeOps,
@@ -6,6 +8,7 @@ import {
   onUnmounted,
   render,
   serializeInner,
+  triggerEvent,
 } from '@vue/runtime-test'
 import {
   type DebuggerEvent,
@@ -958,4 +961,46 @@ describe('reactivity/computed', () => {
       newValue: 2,
     })
   })
+
+  test('should prevent endless recursion in self-referencing computed getters', async () => {
+    const Comp = defineComponent({
+      data() {
+        return {
+          counter: 0,
+        }
+      },
+
+      computed: {
+        message(): string {
+          if (this.counter === 0) {
+            this.counter++
+            return this.message
+          } else {
+            return `Step ${this.counter}`
+          }
+        },
+      },
+
+      render() {
+        return [
+          h(
+            'button',
+            {
+              onClick: () => {
+                this.counter++
+              },
+            },
+            'Step',
+          ),
+          h('p', this.message),
+        ]
+      },
+    })
+    const root = nodeOps.createElement('div')
+    render(h(Comp), root)
+    expect(serializeInner(root)).toBe(`<button>Step</button><p></p>`)
+    triggerEvent(root.children[1] as TestElement, 'click')
+    await nextTick()
+    expect(serializeInner(root)).toBe(`<button>Step</button><p>Step 2</p>`)
+  })
 })

+ 1 - 1
packages/reactivity/src/dep.ts

@@ -46,7 +46,7 @@ export class Dep {
   }
 
   track(debugInfo?: DebuggerEventExtraInfo): Link | undefined {
-    if (!activeSub || !shouldTrack) {
+    if (!activeSub || !shouldTrack || activeSub === this.computed) {
       return
     }