Skip to content

Commit

Permalink
fix(reactivity): fix nested batch edge case
Browse files Browse the repository at this point in the history
  • Loading branch information
yyx990803 committed Sep 27, 2024
1 parent aa9ef23 commit 93c95dd
Show file tree
Hide file tree
Showing 2 changed files with 33 additions and 2 deletions.
31 changes: 31 additions & 0 deletions packages/reactivity/__tests__/watch.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -229,4 +229,35 @@ describe('watch', () => {
expect(r.value).toBe(1)
expect(c.value).toBe(1)
})

// edge case where a nested endBatch() causes an effect to be batched in a
// nested batch loop with its .next mutated, causing the outer loop to end
// early
test('nested batch edge case', () => {
// useClamp from VueUse
const clamp = (n: number, min: number, max: number) =>
Math.min(max, Math.max(min, n))
function useClamp(src: Ref<number>, min: number, max: number) {
return computed({
get() {
return (src.value = clamp(src.value, min, max))
},
set(val) {
src.value = clamp(val, min, max)
},
})
}

const src = ref(1)
const clamped = useClamp(src, 1, 5)
watch(src, val => (clamped.value = val))

const spy = vi.fn()
watch(clamped, spy)

src.value = 2
expect(spy).toHaveBeenCalledTimes(1)
src.value = 10
expect(spy).toHaveBeenCalledTimes(2)
})
})
4 changes: 2 additions & 2 deletions packages/reactivity/src/effect.ts
Original file line number Diff line number Diff line change
Expand Up @@ -274,6 +274,8 @@ export function endBatch(): void {
batchedSub = undefined
// 2nd pass: run effects
while (e) {
next = e.next
e.next = undefined
e.flags &= ~EffectFlags.NOTIFIED
if (e.flags & EffectFlags.ACTIVE) {
try {
Expand All @@ -283,8 +285,6 @@ export function endBatch(): void {
if (!error) error = err
}
}
next = e.next
e.next = undefined
e = next
}
}
Expand Down

0 comments on commit 93c95dd

Please # to comment.