Skip to content

Commit aa9ef23

Browse files
committedSep 27, 2024··
fix(reactivity): only clear notified flags for computed in first batch iteration
close #12045
1 parent 60c2029 commit aa9ef23

File tree

3 files changed

+40
-3
lines changed

3 files changed

+40
-3
lines changed
 

‎packages/reactivity/src/computed.ts

+5-1
Original file line numberDiff line numberDiff line change
@@ -84,9 +84,13 @@ export class ComputedRefImpl<T = any> implements Subscriber {
8484
* @internal
8585
*/
8686
isSSR: boolean
87+
/**
88+
* @internal
89+
*/
90+
next?: Subscriber = undefined
91+
8792
// for backwards compat
8893
effect: this = this
89-
9094
// dev only
9195
onTrack?: (event: DebuggerEvent) => void
9296
// dev only

‎packages/reactivity/src/effect.ts

+8-1
Original file line numberDiff line numberDiff line change
@@ -261,13 +261,20 @@ export function endBatch(): void {
261261
while (batchedSub) {
262262
let e: Subscriber | undefined = batchedSub
263263
let next: Subscriber | undefined
264+
// 1st pass: clear notified flags for computed upfront
265+
// we use the ACTIVE flag as a discriminator between computed and effect,
266+
// since NOTIFIED is useless for an inactive effect anyway.
264267
while (e) {
265-
e.flags &= ~EffectFlags.NOTIFIED
268+
if (!(e.flags & EffectFlags.ACTIVE)) {
269+
e.flags &= ~EffectFlags.NOTIFIED
270+
}
266271
e = e.next
267272
}
268273
e = batchedSub
269274
batchedSub = undefined
275+
// 2nd pass: run effects
270276
while (e) {
277+
e.flags &= ~EffectFlags.NOTIFIED
271278
if (e.flags & EffectFlags.ACTIVE) {
272279
try {
273280
// ACTIVE flag is effect-only

‎packages/runtime-core/__tests__/apiWatch.spec.ts

+27-1
Original file line numberDiff line numberDiff line change
@@ -1930,7 +1930,7 @@ describe('api: watch', () => {
19301930
warn.mockRestore()
19311931
})
19321932

1933-
it('should be executed correctly', () => {
1933+
test('should be executed correctly', () => {
19341934
const v = ref(1)
19351935
let foo = ''
19361936

@@ -1957,4 +1957,30 @@ describe('api: watch', () => {
19571957
v.value++
19581958
expect(foo).toBe('12')
19591959
})
1960+
1961+
// 12045
1962+
test('sync watcher should not break pre watchers', async () => {
1963+
const count1 = ref(0)
1964+
const count2 = ref(0)
1965+
1966+
watch(
1967+
count1,
1968+
() => {
1969+
count2.value++
1970+
},
1971+
{ flush: 'sync' },
1972+
)
1973+
1974+
const spy1 = vi.fn()
1975+
watch([count1, count2], spy1)
1976+
1977+
const spy2 = vi.fn()
1978+
watch(count1, spy2)
1979+
1980+
count1.value++
1981+
1982+
await nextTick()
1983+
expect(spy1).toHaveBeenCalled()
1984+
expect(spy2).toHaveBeenCalled()
1985+
})
19601986
})

0 commit comments

Comments
 (0)
Please sign in to comment.