Skip to content

Commit 93c95dd

Browse files
committedSep 27, 2024··
fix(reactivity): fix nested batch edge case
1 parent aa9ef23 commit 93c95dd

File tree

2 files changed

+33
-2
lines changed

2 files changed

+33
-2
lines changed
 

‎packages/reactivity/__tests__/watch.spec.ts

+31
Original file line numberDiff line numberDiff line change
@@ -229,4 +229,35 @@ describe('watch', () => {
229229
expect(r.value).toBe(1)
230230
expect(c.value).toBe(1)
231231
})
232+
233+
// edge case where a nested endBatch() causes an effect to be batched in a
234+
// nested batch loop with its .next mutated, causing the outer loop to end
235+
// early
236+
test('nested batch edge case', () => {
237+
// useClamp from VueUse
238+
const clamp = (n: number, min: number, max: number) =>
239+
Math.min(max, Math.max(min, n))
240+
function useClamp(src: Ref<number>, min: number, max: number) {
241+
return computed({
242+
get() {
243+
return (src.value = clamp(src.value, min, max))
244+
},
245+
set(val) {
246+
src.value = clamp(val, min, max)
247+
},
248+
})
249+
}
250+
251+
const src = ref(1)
252+
const clamped = useClamp(src, 1, 5)
253+
watch(src, val => (clamped.value = val))
254+
255+
const spy = vi.fn()
256+
watch(clamped, spy)
257+
258+
src.value = 2
259+
expect(spy).toHaveBeenCalledTimes(1)
260+
src.value = 10
261+
expect(spy).toHaveBeenCalledTimes(2)
262+
})
232263
})

‎packages/reactivity/src/effect.ts

+2-2
Original file line numberDiff line numberDiff line change
@@ -274,6 +274,8 @@ export function endBatch(): void {
274274
batchedSub = undefined
275275
// 2nd pass: run effects
276276
while (e) {
277+
next = e.next
278+
e.next = undefined
277279
e.flags &= ~EffectFlags.NOTIFIED
278280
if (e.flags & EffectFlags.ACTIVE) {
279281
try {
@@ -283,8 +285,6 @@ export function endBatch(): void {
283285
if (!error) error = err
284286
}
285287
}
286-
next = e.next
287-
e.next = undefined
288288
e = next
289289
}
290290
}

0 commit comments

Comments
 (0)
Please sign in to comment.