Skip to content

Commit

Permalink
fix(reactivity): only clear notified flags for computed in first batc…
Browse files Browse the repository at this point in the history
…h iteration

close #12045
  • Loading branch information
yyx990803 committed Sep 27, 2024
1 parent 60c2029 commit aa9ef23
Show file tree
Hide file tree
Showing 3 changed files with 40 additions and 3 deletions.
6 changes: 5 additions & 1 deletion packages/reactivity/src/computed.ts
Original file line number Diff line number Diff line change
Expand Up @@ -84,9 +84,13 @@ export class ComputedRefImpl<T = any> implements Subscriber {
* @internal
*/
isSSR: boolean
/**
* @internal
*/
next?: Subscriber = undefined

// for backwards compat
effect: this = this

// dev only
onTrack?: (event: DebuggerEvent) => void
// dev only
Expand Down
9 changes: 8 additions & 1 deletion packages/reactivity/src/effect.ts
Original file line number Diff line number Diff line change
Expand Up @@ -261,13 +261,20 @@ export function endBatch(): void {
while (batchedSub) {
let e: Subscriber | undefined = batchedSub
let next: Subscriber | undefined
// 1st pass: clear notified flags for computed upfront
// we use the ACTIVE flag as a discriminator between computed and effect,
// since NOTIFIED is useless for an inactive effect anyway.
while (e) {
e.flags &= ~EffectFlags.NOTIFIED
if (!(e.flags & EffectFlags.ACTIVE)) {
e.flags &= ~EffectFlags.NOTIFIED
}
e = e.next
}
e = batchedSub
batchedSub = undefined
// 2nd pass: run effects
while (e) {
e.flags &= ~EffectFlags.NOTIFIED
if (e.flags & EffectFlags.ACTIVE) {
try {
// ACTIVE flag is effect-only
Expand Down
28 changes: 27 additions & 1 deletion packages/runtime-core/__tests__/apiWatch.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1930,7 +1930,7 @@ describe('api: watch', () => {
warn.mockRestore()
})

it('should be executed correctly', () => {
test('should be executed correctly', () => {
const v = ref(1)
let foo = ''

Expand All @@ -1957,4 +1957,30 @@ describe('api: watch', () => {
v.value++
expect(foo).toBe('12')
})

// 12045
test('sync watcher should not break pre watchers', async () => {
const count1 = ref(0)
const count2 = ref(0)

watch(
count1,
() => {
count2.value++
},
{ flush: 'sync' },
)

const spy1 = vi.fn()
watch([count1, count2], spy1)

const spy2 = vi.fn()
watch(count1, spy2)

count1.value++

await nextTick()
expect(spy1).toHaveBeenCalled()
expect(spy2).toHaveBeenCalled()
})
})

0 comments on commit aa9ef23

Please sign in to comment.