Просмотр исходного кода

fix(watch): template ref watcher should fire after owner instance mounted hook

fix #12578
Evan You 3 лет назад
Родитель
Сommit
089b27c30b
2 измененных файлов с 29 добавлено и 5 удалено
  1. 4 3
      src/v3/apiWatch.ts
  2. 25 2
      test/unit/features/v3/apiWatch.spec.ts

+ 4 - 3
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)
       }
     }
   }

+ 25 - 2
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: '<div/>' }
+    const App = {
+      setup() {
+        const child = ref<any>(null)
+        onMounted(() => {
+          order.push('mounted')
+        })
+        watch(child, () => {
+          order.push('watcher')
+        })
+        return { child }
+      },
+      components: { Child },
+      template: `<Child ref="child"/>`
+    }
+    new Vue(App).$mount()
+
+    await nextTick()
+    expect(order).toMatchObject([`mounted`, `watcher`])
+  })
 })