فهرست منبع

fix(reactivity): ensure computed is invalidated before other effects

fix #5720
Evan You 4 سال پیش
والد
کامیت
82bdf86254
2فایلهای تغییر یافته به همراه42 افزوده شده و 10 حذف شده
  1. 17 0
      packages/reactivity/__tests__/computed.spec.ts
  2. 25 10
      packages/reactivity/src/effect.ts

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

@@ -170,6 +170,23 @@ describe('reactivity/computed', () => {
     expect(dummy).toBe(-1)
   })
 
+  // #5720
+  it('should invalidate before non-computed effects', () => {
+    let plusOneValues: number[] = []
+    const n = ref(0)
+    const plusOne = computed(() => n.value + 1)
+    effect(() => {
+      n.value
+      plusOneValues.push(plusOne.value)
+    })
+    // access plusOne, causing it to be non-dirty
+    plusOne.value
+    // mutate n
+    n.value++
+    // on the 2nd run, plusOne.value should have already updated.
+    expect(plusOneValues).toMatchObject([1, 2, 2])
+  })
+
   it('should warn if trying to set a readonly computed', () => {
     const n = ref(1)
     const plusOne = computed(() => n.value + 1)

+ 25 - 10
packages/reactivity/src/effect.ts

@@ -348,16 +348,31 @@ export function triggerEffects(
   debuggerEventExtraInfo?: DebuggerEventExtraInfo
 ) {
   // spread into array for stabilization
-  for (const effect of isArray(dep) ? dep : [...dep]) {
-    if (effect !== activeEffect || effect.allowRecurse) {
-      if (__DEV__ && effect.onTrigger) {
-        effect.onTrigger(extend({ effect }, debuggerEventExtraInfo))
-      }
-      if (effect.scheduler) {
-        effect.scheduler()
-      } else {
-        effect.run()
-      }
+  const effects = isArray(dep) ? dep : [...dep]
+  for (const effect of effects) {
+    if (effect.computed) {
+      triggerEffect(effect, debuggerEventExtraInfo)
+    }
+  }
+  for (const effect of effects) {
+    if (!effect.computed) {
+      triggerEffect(effect, debuggerEventExtraInfo)
+    }
+  }
+}
+
+function triggerEffect(
+  effect: ReactiveEffect,
+  debuggerEventExtraInfo?: DebuggerEventExtraInfo
+) {
+  if (effect !== activeEffect || effect.allowRecurse) {
+    if (__DEV__ && effect.onTrigger) {
+      effect.onTrigger(extend({ effect }, debuggerEventExtraInfo))
+    }
+    if (effect.scheduler) {
+      effect.scheduler()
+    } else {
+      effect.run()
     }
   }
 }