diff --git a/src/v3/apiWatch.ts b/src/v3/apiWatch.ts index 909bd0258ec..4d387dc1c1a 100644 --- a/src/v3/apiWatch.ts +++ b/src/v3/apiWatch.ts @@ -320,11 +320,12 @@ function doWatch( } else { // pre watcher.update = () => { - if (!instance || instance._isMounted) { - queueWatcher(watcher) - } else { + if (instance && instance === currentInstance) { + // pre-watcher triggered inside setup() const buffer = instance._preWatchers || (instance._preWatchers = []) if (buffer.indexOf(watcher) < 0) buffer.push(watcher) + } else { + queueWatcher(watcher) } } } diff --git a/test/unit/features/v3/apiWatch.spec.ts b/test/unit/features/v3/apiWatch.spec.ts index 85ee2ef8400..82aba414ce0 100644 --- a/test/unit/features/v3/apiWatch.spec.ts +++ b/test/unit/features/v3/apiWatch.spec.ts @@ -628,9 +628,8 @@ describe('api: watch', () => { expect(calls).toMatchObject(['watch 3', 'mounted']) }) - // TODO // vuejs/core#1852 - it.skip('flush: post watcher should fire after template refs updated', async () => { + it('flush: post watcher should fire after template refs updated', async () => { const toggle = ref(false) let dom: HTMLElement | null = null @@ -1093,4 +1092,28 @@ describe('api: watch', () => { // own update effect expect(instance!._scope.effects.length).toBe(1) }) + + // #12578 + test('template ref triggered watcher should fire after component mount', async () => { + const order: string[] = [] + const Child = { template: '
' } + const App = { + setup() { + const child = ref(null) + onMounted(() => { + order.push('mounted') + }) + watch(child, () => { + order.push('watcher') + }) + return { child } + }, + components: { Child }, + template: `` + } + new Vue(App).$mount() + + await nextTick() + expect(order).toMatchObject([`mounted`, `watcher`]) + }) })