From 5d52d1984bc9ee18bd60db6e23abbc9891cb1802 Mon Sep 17 00:00:00 2001 From: Doctor Wu Date: Thu, 27 Jun 2024 22:45:04 +0800 Subject: [PATCH] fix(reactivity): fix effect not schedule when trigger maybedirty close #11236 --- .../reactivity/__tests__/computed.spec.ts | 34 +++++++++++++++++++ packages/reactivity/src/effect.ts | 28 ++++++++++----- 2 files changed, 53 insertions(+), 9 deletions(-) diff --git a/packages/reactivity/__tests__/computed.spec.ts b/packages/reactivity/__tests__/computed.spec.ts index 9a91eed6389..e7db396e880 100644 --- a/packages/reactivity/__tests__/computed.spec.ts +++ b/packages/reactivity/__tests__/computed.spec.ts @@ -765,6 +765,40 @@ describe('reactivity/computed', () => { expect(COMPUTED_SIDE_EFFECT_WARN).toHaveBeenWarned() }) + // #11236 + it('should schedule effect when trigger maybedirty', async () => { + const foo = ref({}) + + const bar = computed(() => { + foo.value.bar ??= {} + return foo.value.bar + }) + + const baz = computed(() => { + bar.value.baz ??= [] + return bar.value.baz + }) + + const qux = computed(() => baz.value.at(-1) === 2) + + const Comp = { + render: () => h('div', [JSON.stringify(qux.value)]), + } + const root = nodeOps.createElement('div') + render(h(Comp), root) + await nextTick() + expect(serializeInner(root)).toBe('
false
') + + baz.value.push(1) + await nextTick() + expect(serializeInner(root)).toBe('
false
') + + baz.value.push(2) + await nextTick() + expect(serializeInner(root)).toBe('
true
') + expect(COMPUTED_SIDE_EFFECT_WARN).toHaveBeenWarned() + }) + it('debug: onTrigger (ref)', () => { let events: DebuggerEvent[] = [] const onTrigger = vi.fn((e: DebuggerEvent) => { diff --git a/packages/reactivity/src/effect.ts b/packages/reactivity/src/effect.ts index 6817931f0e5..1c44b52b972 100644 --- a/packages/reactivity/src/effect.ts +++ b/packages/reactivity/src/effect.ts @@ -325,15 +325,7 @@ export function triggerEffects( effect._dirtyLevel < dirtyLevel && (tracking ??= dep.get(effect) === effect._trackId) ) { - effect._shouldSchedule ||= effect._dirtyLevel === DirtyLevels.NotDirty - // always schedule if the computed is original side effect - // since we know it is actually dirty - if ( - effect.computed && - effect._dirtyLevel === DirtyLevels.MaybeDirty_ComputedSideEffect_Origin - ) { - effect._shouldSchedule = true - } + resolveSchedule(effect, dirtyLevel) effect._dirtyLevel = dirtyLevel } if ( @@ -358,3 +350,21 @@ export function triggerEffects( } resetScheduling() } + +function resolveSchedule(effect: ReactiveEffect, dirtyLevel: DirtyLevels) { + effect._shouldSchedule ||= effect._dirtyLevel === DirtyLevels.NotDirty + // always schedule if the computed is original side effect + // since we know it is actually dirty + if ( + effect.computed && + effect._dirtyLevel === DirtyLevels.MaybeDirty_ComputedSideEffect_Origin + ) { + effect._shouldSchedule = true + } + if ( + effect._dirtyLevel === DirtyLevels.MaybeDirty_ComputedSideEffect && + dirtyLevel > DirtyLevels.MaybeDirty_ComputedSideEffect + ) { + effect._shouldSchedule = true + } +}