diff --git a/packages/runtime-core/__tests__/apiWatch.spec.ts b/packages/runtime-core/__tests__/apiWatch.spec.ts index a5517ab1..572ac11d 100644 --- a/packages/runtime-core/__tests__/apiWatch.spec.ts +++ b/packages/runtime-core/__tests__/apiWatch.spec.ts @@ -18,7 +18,8 @@ import { h, createApp, watchPostEffect, - watchSyncEffect + watchSyncEffect, + onMounted } from '@vue/runtime-test' import { ITERATE_KEY, @@ -581,6 +582,33 @@ describe('api: watch', () => { expect(calls).toEqual(['render', 'watcher 1', 'watcher 2', 'render']) }) + // #5721 + it('flush: pre triggered in component setup should be buffered and called before mounted', () => { + const count = ref(0) + const calls: string[] = [] + const App = { + render() {}, + setup() { + watch( + count, + () => { + calls.push('watch ' + count.value) + }, + { flush: 'pre' } + ) + onMounted(() => { + calls.push('mounted') + }) + // mutate multiple times + count.value++ + count.value++ + count.value++ + } + } + render(h(App), nodeOps.createElement('div')) + expect(calls).toMatchObject(['watch 3', 'mounted']) + }) + // #1852 it('flush: post watcher should fire after template refs updated', async () => { const toggle = ref(false) diff --git a/packages/runtime-core/src/apiWatch.ts b/packages/runtime-core/src/apiWatch.ts index 881a04a6..84937eea 100644 --- a/packages/runtime-core/src/apiWatch.ts +++ b/packages/runtime-core/src/apiWatch.ts @@ -345,15 +345,7 @@ function doWatch( scheduler = () => queuePostRenderEffect(job, instance && instance.suspense) } else { // default: 'pre' - scheduler = () => { - if (!instance || instance.isMounted) { - queuePreFlushCb(job) - } else { - // with 'pre' option, the first call must happen before - // the component is mounted so it is called synchronously. - job() - } - } + scheduler = () => queuePreFlushCb(job) } const effect = new ReactiveEffect(getter, scheduler) diff --git a/packages/runtime-core/src/scheduler.ts b/packages/runtime-core/src/scheduler.ts index fbf18deb..2056d80e 100644 --- a/packages/runtime-core/src/scheduler.ts +++ b/packages/runtime-core/src/scheduler.ts @@ -182,6 +182,8 @@ export function flushPreFlushCbs( } export function flushPostFlushCbs(seen?: CountMap) { + // flush any pre cbs queued during the flush (e.g. pre watchers) + flushPreFlushCbs() if (pendingPostFlushCbs.length) { const deduped = [...new Set(pendingPostFlushCbs)] pendingPostFlushCbs.length = 0