]> git.ipfire.org Git - thirdparty/vuejs/core.git/commitdiff
fix(runtime-core/template-ref): template ref used in the same template should trigger...
authorEvan You <yyx990803@gmail.com>
Mon, 6 Jul 2020 20:40:00 +0000 (16:40 -0400)
committerEvan You <yyx990803@gmail.com>
Mon, 6 Jul 2020 20:40:00 +0000 (16:40 -0400)
fix #1505

packages/runtime-core/__tests__/apiTemplateRef.spec.ts
packages/runtime-core/src/hydration.ts
packages/runtime-core/src/renderer.ts

index 20d074fa1f97efb05fe1d696871d9a0407f55ef9..cb5da3a9533aa7181dc9ca25b6b9b58db4b7f2a7 100644 (file)
@@ -5,7 +5,8 @@ import {
   render,
   nextTick,
   defineComponent,
-  reactive
+  reactive,
+  serializeInner
 } from '@vue/runtime-test'
 
 // reference: https://vue-composition-api-rfc.netlify.com/api.html#template-refs
@@ -246,4 +247,25 @@ describe('api: template refs', () => {
     expect(refKey2.value).toBe(root.children[2])
     expect(refKey3.value).toBe(root.children[3])
   })
+
+  // #1505
+  test('reactive template ref in the same template', async () => {
+    const Comp = {
+      setup() {
+        const el = ref()
+        return { el }
+      },
+      render(this: any) {
+        return h('div', { id: 'foo', ref: 'el' }, this.el && this.el.props.id)
+      }
+    }
+
+    const root = nodeOps.createElement('div')
+    render(h(Comp), root)
+    // ref not ready on first render, but should queue an update immediately
+    expect(serializeInner(root)).toBe(`<div id="foo"></div>`)
+    await nextTick()
+    // ref should be updated
+    expect(serializeInner(root)).toBe(`<div id="foo">foo</div>`)
+  })
 })
index b0d455b0af4337b5283550ffa7a0d2967992ae22..62d9e6f0a09f5a2740f549f959467f845b2e3b13 100644 (file)
@@ -227,7 +227,7 @@ export function createHydrationFunctions(
     }
 
     if (ref != null && parentComponent) {
-      setRef(ref, null, parentComponent, vnode)
+      setRef(ref, null, parentComponent, parentSuspense, vnode)
     }
 
     return nextNode
index de69659b050e92f090dcfc1a275c1cbc4f2ca373..2c827136a9fcd0dab3e8980069b81a32694a11c2 100644 (file)
@@ -275,7 +275,8 @@ export const queuePostRenderEffect = __FEATURE_SUSPENSE__
 export const setRef = (
   rawRef: VNodeNormalizedRef,
   oldRawRef: VNodeNormalizedRef | null,
-  parent: ComponentInternalInstance,
+  parentComponent: ComponentInternalInstance,
+  parentSuspense: SuspenseBoundary | null,
   vnode: VNode | null
 ) => {
   let value: ComponentPublicInstance | RendererNode | null
@@ -306,7 +307,9 @@ export const setRef = (
     if (isString(oldRef)) {
       refs[oldRef] = null
       if (hasOwn(setupState, oldRef)) {
-        setupState[oldRef] = null
+        queuePostRenderEffect(() => {
+          setupState[oldRef] = null
+        }, parentSuspense)
       }
     } else if (isRef(oldRef)) {
       oldRef.value = null
@@ -316,12 +319,17 @@ export const setRef = (
   if (isString(ref)) {
     refs[ref] = value
     if (hasOwn(setupState, ref)) {
-      setupState[ref] = value
+      queuePostRenderEffect(() => {
+        setupState[ref] = value
+      }, parentSuspense)
     }
   } else if (isRef(ref)) {
     ref.value = value
   } else if (isFunction(ref)) {
-    callWithErrorHandling(ref, parent, ErrorCodes.FUNCTION_REF, [value, refs])
+    callWithErrorHandling(ref, parentComponent, ErrorCodes.FUNCTION_REF, [
+      value,
+      refs
+    ])
   } else if (__DEV__) {
     warn('Invalid template ref type:', value, `(${typeof value})`)
   }
@@ -497,7 +505,7 @@ function baseCreateRenderer(
 
     // set ref
     if (ref != null && parentComponent) {
-      setRef(ref, n1 && n1.ref, parentComponent, n2)
+      setRef(ref, n1 && n1.ref, parentComponent, parentSuspense, n2)
     }
   }
 
@@ -1868,7 +1876,7 @@ function baseCreateRenderer(
     } = vnode
     // unset ref
     if (ref != null && parentComponent) {
-      setRef(ref, null, parentComponent, null)
+      setRef(ref, null, parentComponent, parentSuspense, null)
     }
 
     if (shapeFlag & ShapeFlags.COMPONENT_SHOULD_KEEP_ALIVE) {