Skip to content

Commit

Permalink
fix(reactive): fix wrong reaction._boundary
Browse files Browse the repository at this point in the history
  • Loading branch information
meowtec committed Dec 30, 2024
1 parent 5472532 commit 2ada729
Show file tree
Hide file tree
Showing 4 changed files with 54 additions and 12 deletions.
21 changes: 21 additions & 0 deletions packages/reactive/src/__tests__/autorun.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -741,3 +741,24 @@ test('reaction recollect dependencies', () => {
expect(fn2).toBeCalledTimes(2)
expect(trigger2).toBeCalledTimes(2)
})

test('accurate boundary', () => {
const obs = observable<any>({
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')
})
9 changes: 8 additions & 1 deletion packages/reactive/src/environment.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,12 +8,19 @@ export const RawShallowProxy = new WeakMap()
export const RawNode = new WeakMap<object, DataNode>()
export const RawReactionsMap = new WeakMap<object, ReactionsMap>()

export type PendingReactions = ArraySet<Reaction>

export const createPendingReactions = (): PendingReactions =>
new ArraySet<Reaction>()

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<Reaction>()
export const PendingReactionsRef: { value: PendingReactions | null } = {
value: null,
}
export const PendingScopeReactions = new ArraySet<Reaction>()
export const BatchEndpoints = new ArraySet<() => void>()
export const ObserverListeners = new ArraySet<ObservableListener>()
Expand Down
35 changes: 24 additions & 11 deletions packages/reactive/src/reaction.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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')
Expand Down Expand Up @@ -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)) {
Expand Down Expand Up @@ -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
}
Expand Down Expand Up @@ -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 = () => {
Expand Down
1 change: 1 addition & 0 deletions packages/reactive/src/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -79,6 +79,7 @@ export type Reaction = ((...args: any[]) => any) & {
queue: IEffectQueueItem[]
cursor: number
}
_pending?: boolean
}

export type ReactionsMap = Map<PropertyKey, ArraySet<Reaction>>
Expand Down

0 comments on commit 2ada729

Please sign in to comment.