diff --git a/packages/runtime-core/__tests__/rendererComponent.spec.ts b/packages/runtime-core/__tests__/rendererComponent.spec.ts index c5faa05de83..fefc4137034 100644 --- a/packages/runtime-core/__tests__/rendererComponent.spec.ts +++ b/packages/runtime-core/__tests__/rendererComponent.spec.ts @@ -236,6 +236,105 @@ describe('renderer: component', () => { expect(serializeInner(root)).toBe(`
1
1
`) }) + test('child only updates once when triggered in multiple ways', async () => { + const a = ref(0) + const calls: string[] = [] + + const Parent = { + setup() { + return () => { + calls.push('render parent') + return h(Child, { count: a.value }, () => a.value) + } + }, + } + + const Child = { + props: ['count'], + setup(props: any) { + return () => { + calls.push('render child') + return `${props.count} - ${a.value}` + } + }, + } + + render(h(Parent), nodeOps.createElement('div')) + expect(calls).toEqual(['render parent', 'render child']) + + // This will trigger child rendering directly, as well as via a prop change + a.value++ + await nextTick() + expect(calls).toEqual([ + 'render parent', + 'render child', + 'render parent', + 'render child', + ]) + }) + + // #7745 + test(`an earlier update doesn't lead to excessive subsequent updates`, async () => { + const globalCount = ref(0) + const parentCount = ref(0) + const calls: string[] = [] + + const Root = { + setup() { + return () => { + calls.push('render root') + return h(Parent, { count: globalCount.value }) + } + }, + } + + const Parent = { + props: ['count'], + setup(props: any) { + return () => { + calls.push('render parent') + return [ + `${globalCount.value} - ${props.count}`, + h(Child, { count: parentCount.value }), + ] + } + }, + } + + const Child = { + props: ['count'], + setup(props: any) { + watch( + () => props.count, + () => { + calls.push('child watcher') + globalCount.value = props.count + }, + ) + + return () => { + calls.push('render child') + } + }, + } + + render(h(Root), nodeOps.createElement('div')) + expect(calls).toEqual(['render root', 'render parent', 'render child']) + + parentCount.value++ + await nextTick() + expect(calls).toEqual([ + 'render root', + 'render parent', + 'render child', + 'render parent', + 'child watcher', + 'render child', + 'render root', + 'render parent', + ]) + }) + // #2521 test('should pause tracking deps when initializing legacy options', async () => { let childInstance = null as any diff --git a/packages/runtime-core/__tests__/scheduler.spec.ts b/packages/runtime-core/__tests__/scheduler.spec.ts index 8d74330da44..5c5b04673ab 100644 --- a/packages/runtime-core/__tests__/scheduler.spec.ts +++ b/packages/runtime-core/__tests__/scheduler.spec.ts @@ -3,7 +3,6 @@ import { SchedulerJobFlags, flushPostFlushCbs, flushPreFlushCbs, - invalidateJob, nextTick, queueJob, queuePostFlushCb, @@ -444,33 +443,6 @@ describe('scheduler', () => { }) }) - test('invalidateJob', async () => { - const calls: string[] = [] - const job1 = () => { - calls.push('job1') - invalidateJob(job2) - job2() - } - const job2 = () => { - calls.push('job2') - } - const job3 = () => { - calls.push('job3') - } - const job4 = () => { - calls.push('job4') - } - // queue all jobs - queueJob(job1) - queueJob(job2) - queueJob(job3) - queuePostFlushCb(job4) - expect(calls).toEqual([]) - await nextTick() - // job2 should be called only once - expect(calls).toEqual(['job1', 'job2', 'job3', 'job4']) - }) - test('sort job based on id', async () => { const calls: string[] = [] const job1 = () => calls.push('job1') diff --git a/packages/runtime-core/src/renderer.ts b/packages/runtime-core/src/renderer.ts index 3d1cc6849c7..ce063989502 100644 --- a/packages/runtime-core/src/renderer.ts +++ b/packages/runtime-core/src/renderer.ts @@ -45,7 +45,6 @@ import { type SchedulerJobs, flushPostFlushCbs, flushPreFlushCbs, - invalidateJob, queueJob, queuePostFlushCb, } from './scheduler' @@ -1255,9 +1254,6 @@ function baseCreateRenderer( } else { // normal update instance.next = n2 - // in case the child component is also queued, remove it to avoid - // double updating the same child component in the same flush. - invalidateJob(instance.update) // instance.update is the reactive effect. instance.update() } diff --git a/packages/runtime-core/src/scheduler.ts b/packages/runtime-core/src/scheduler.ts index 256ab202780..aa12b6896a7 100644 --- a/packages/runtime-core/src/scheduler.ts +++ b/packages/runtime-core/src/scheduler.ts @@ -122,13 +122,6 @@ function queueFlush() { } } -export function invalidateJob(job: SchedulerJob): void { - const i = queue.indexOf(job) - if (i > flushIndex) { - queue.splice(i, 1) - } -} - export function queuePostFlushCb(cb: SchedulerJobs): void { if (!isArray(cb)) { if (activePostFlushCbs && cb.id === -1) {