From 2ada729867fc294c28361ba792ef9adfff6e60dc Mon Sep 17 00:00:00 2001 From: meowtec Date: Mon, 30 Dec 2024 19:12:43 +0800 Subject: [PATCH] fix(reactive): fix wrong reaction._boundary --- .../reactive/src/__tests__/autorun.spec.ts | 21 +++++++++++ packages/reactive/src/environment.ts | 9 ++++- packages/reactive/src/reaction.ts | 35 +++++++++++++------ packages/reactive/src/types.ts | 1 + 4 files changed, 54 insertions(+), 12 deletions(-) diff --git a/packages/reactive/src/__tests__/autorun.spec.ts b/packages/reactive/src/__tests__/autorun.spec.ts index 2e74766b38a..3c6a6379aad 100644 --- a/packages/reactive/src/__tests__/autorun.spec.ts +++ b/packages/reactive/src/__tests__/autorun.spec.ts @@ -741,3 +741,24 @@ test('reaction recollect dependencies', () => { expect(fn2).toBeCalledTimes(2) expect(trigger2).toBeCalledTimes(2) }) + +test('accurate boundary', () => { + const obs = observable({ + a: '', + b: '', + c: '', + }) + + autorun(() => { + obs.c = obs.a + obs.b + }) + + autorun(() => { + obs.b = obs.a + }) + + obs.a = 'a' + expect(obs.a).toBe('a') + expect(obs.b).toBe('a') + expect(obs.c).toBe('aa') +}) diff --git a/packages/reactive/src/environment.ts b/packages/reactive/src/environment.ts index 52b769fb0ed..b0317b4fb77 100644 --- a/packages/reactive/src/environment.ts +++ b/packages/reactive/src/environment.ts @@ -8,12 +8,19 @@ export const RawShallowProxy = new WeakMap() export const RawNode = new WeakMap() export const RawReactionsMap = new WeakMap() +export type PendingReactions = ArraySet + +export const createPendingReactions = (): PendingReactions => + new ArraySet() + export const ReactionStack: Reaction[] = [] export const BatchCount = { value: 0 } export const UntrackCount = { value: 0 } export const BatchScope = { value: false } export const DependencyCollected = { value: false } -export const PendingReactions = new ArraySet() +export const PendingReactionsRef: { value: PendingReactions | null } = { + value: null, +} export const PendingScopeReactions = new ArraySet() export const BatchEndpoints = new ArraySet<() => void>() export const ObserverListeners = new ArraySet() diff --git a/packages/reactive/src/reaction.ts b/packages/reactive/src/reaction.ts index 543d5ec931e..cce4db9493e 100644 --- a/packages/reactive/src/reaction.ts +++ b/packages/reactive/src/reaction.ts @@ -4,14 +4,16 @@ import { IOperation, ReactionsMap, Reaction, PropertyKey } from './types' import { ReactionStack, PendingScopeReactions, - BatchEndpoints, DependencyCollected, RawReactionsMap, - PendingReactions, + PendingReactionsRef, BatchCount, UntrackCount, BatchScope, ObserverListeners, + PendingReactions, + BatchEndpoints, + createPendingReactions, } from './environment' const ITERATION_KEY = Symbol('iteration key') @@ -79,7 +81,11 @@ const runReactions = (target: any, key: PropertyKey) => { } else if (isScopeBatching()) { PendingScopeReactions.add(reaction) } else if (isBatching()) { - PendingReactions.add(reaction) + if (!reaction._pending) { + reaction._pending = true + ;(PendingReactionsRef.value = + PendingReactionsRef.value || createPendingReactions()).add(reaction) + } } else { // never reach if (isFn(reaction._scheduler)) { @@ -153,7 +159,8 @@ export const releaseBindingReactions = (reaction: Reaction) => { reactions.delete(reaction) }) }) - PendingReactions.delete(reaction) + reaction._pending = false + PendingReactionsRef.value?.delete(reaction) PendingScopeReactions.delete(reaction) delete reaction._reactionsSet } @@ -225,13 +232,19 @@ export const isScopeBatching = () => BatchScope.value export const isUntracking = () => UntrackCount.value > 0 export const executePendingReactions = () => { - PendingReactions.batchDelete((reaction) => { - if (isFn(reaction._scheduler)) { - reaction._scheduler(reaction) - } else { - reaction() - } - }) + while (PendingReactionsRef.value) { + const PendingReactions = PendingReactionsRef.value + PendingReactionsRef.value = null + PendingReactions.batchDelete((reaction) => { + if (!reaction._pending) return + reaction._pending = false + if (isFn(reaction._scheduler)) { + reaction._scheduler(reaction) + } else { + reaction() + } + }) + } } export const executeBatchEndpoints = () => { diff --git a/packages/reactive/src/types.ts b/packages/reactive/src/types.ts index f0fcca41185..8b8d1bdd860 100644 --- a/packages/reactive/src/types.ts +++ b/packages/reactive/src/types.ts @@ -79,6 +79,7 @@ export type Reaction = ((...args: any[]) => any) & { queue: IEffectQueueItem[] cursor: number } + _pending?: boolean } export type ReactionsMap = Map>