diff --git a/packages/runtime-core/__tests__/apiTemplateRef.spec.ts b/packages/runtime-core/__tests__/apiTemplateRef.spec.ts
index 20d074fa1f9..cb5da3a9533 100644
--- a/packages/runtime-core/__tests__/apiTemplateRef.spec.ts
+++ b/packages/runtime-core/__tests__/apiTemplateRef.spec.ts
@@ -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(`
`)
+ await nextTick()
+ // ref should be updated
+ expect(serializeInner(root)).toBe(`foo
`)
+ })
})
diff --git a/packages/runtime-core/src/hydration.ts b/packages/runtime-core/src/hydration.ts
index b0d455b0af4..62d9e6f0a09 100644
--- a/packages/runtime-core/src/hydration.ts
+++ b/packages/runtime-core/src/hydration.ts
@@ -227,7 +227,7 @@ export function createHydrationFunctions(
}
if (ref != null && parentComponent) {
- setRef(ref, null, parentComponent, vnode)
+ setRef(ref, null, parentComponent, parentSuspense, vnode)
}
return nextNode
diff --git a/packages/runtime-core/src/renderer.ts b/packages/runtime-core/src/renderer.ts
index de69659b050..2c827136a9f 100644
--- a/packages/runtime-core/src/renderer.ts
+++ b/packages/runtime-core/src/renderer.ts
@@ -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) {