]> git.ipfire.org Git - thirdparty/vuejs/core.git/commitdiff
fix(reactivity): should not recompute if computed does not track reactive data (...
authoredison <daiwei521@126.com>
Thu, 1 May 2025 14:02:17 +0000 (22:02 +0800)
committerGitHub <noreply@github.com>
Thu, 1 May 2025 14:02:17 +0000 (07:02 -0700)
close #12337

packages/reactivity/__tests__/computed.spec.ts
packages/reactivity/src/effect.ts

index 123df44f2539ab13fcb45ea42440d02cdb3b3e38..c7963499f858882abe2015bd61bf50ae98c5d93f 100644 (file)
@@ -1012,6 +1012,17 @@ describe('reactivity/computed', () => {
     expect(cValue.value).toBe(1)
   })
 
+  test('should not recompute if computed does not track reactive data', async () => {
+    const spy = vi.fn()
+    const c1 = computed(() => spy())
+
+    c1.value
+    ref(0).value++ // update globalVersion
+    c1.value
+
+    expect(spy).toBeCalledTimes(1)
+  })
+
   test('computed should remain live after losing all subscribers', () => {
     const state = reactive({ a: 1 })
     const p = computed(() => state.a + 1)
index 886f380dd521db5af93da8d4bfac31ec0a919db5..84cf184c154a6fc06b6ca5314bb4379f4ce56ff4 100644 (file)
@@ -49,6 +49,7 @@ export enum EffectFlags {
   DIRTY = 1 << 4,
   ALLOW_RECURSE = 1 << 5,
   PAUSED = 1 << 6,
+  EVALUATED = 1 << 7,
 }
 
 /**
@@ -377,22 +378,22 @@ export function refreshComputed(computed: ComputedRefImpl): undefined {
   }
   computed.globalVersion = globalVersion
 
-  const dep = computed.dep
-  computed.flags |= EffectFlags.RUNNING
   // In SSR there will be no render effect, so the computed has no subscriber
   // and therefore tracks no deps, thus we cannot rely on the dirty check.
   // Instead, computed always re-evaluate and relies on the globalVersion
   // fast path above for caching.
+  // #12337 if computed has no deps (does not rely on any reactive data) and evaluated,
+  // there is no need to re-evaluate.
   if (
-    dep.version > 0 &&
     !computed.isSSR &&
-    computed.deps &&
-    !isDirty(computed)
+    computed.flags & EffectFlags.EVALUATED &&
+    ((!computed.deps && !(computed as any)._dirty) || !isDirty(computed))
   ) {
-    computed.flags &= ~EffectFlags.RUNNING
     return
   }
+  computed.flags |= EffectFlags.RUNNING
 
+  const dep = computed.dep
   const prevSub = activeSub
   const prevShouldTrack = shouldTrack
   activeSub = computed
@@ -402,6 +403,7 @@ export function refreshComputed(computed: ComputedRefImpl): undefined {
     prepareDeps(computed)
     const value = computed.fn(computed._value)
     if (dep.version === 0 || hasChanged(value, computed._value)) {
+      computed.flags |= EffectFlags.EVALUATED
       computed._value = value
       dep.version++
     }