Skip to content

Commit 36b6b4f

Browse files
committed
fix(runtime-core/template-ref): template ref used in the same template should trigger update
fix #1505
1 parent 64e2f46 commit 36b6b4f

File tree

3 files changed

+38
-8
lines changed

3 files changed

+38
-8
lines changed

packages/runtime-core/__tests__/apiTemplateRef.spec.ts

+23-1
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,8 @@ import {
55
render,
66
nextTick,
77
defineComponent,
8-
reactive
8+
reactive,
9+
serializeInner
910
} from '@vue/runtime-test'
1011

1112
// reference: https://vue-composition-api-rfc.netlify.com/api.html#template-refs
@@ -246,4 +247,25 @@ describe('api: template refs', () => {
246247
expect(refKey2.value).toBe(root.children[2])
247248
expect(refKey3.value).toBe(root.children[3])
248249
})
250+
251+
// #1505
252+
test('reactive template ref in the same template', async () => {
253+
const Comp = {
254+
setup() {
255+
const el = ref()
256+
return { el }
257+
},
258+
render(this: any) {
259+
return h('div', { id: 'foo', ref: 'el' }, this.el && this.el.props.id)
260+
}
261+
}
262+
263+
const root = nodeOps.createElement('div')
264+
render(h(Comp), root)
265+
// ref not ready on first render, but should queue an update immediately
266+
expect(serializeInner(root)).toBe(`<div id="foo"></div>`)
267+
await nextTick()
268+
// ref should be updated
269+
expect(serializeInner(root)).toBe(`<div id="foo">foo</div>`)
270+
})
249271
})

packages/runtime-core/src/hydration.ts

+1-1
Original file line numberDiff line numberDiff line change
@@ -227,7 +227,7 @@ export function createHydrationFunctions(
227227
}
228228

229229
if (ref != null && parentComponent) {
230-
setRef(ref, null, parentComponent, vnode)
230+
setRef(ref, null, parentComponent, parentSuspense, vnode)
231231
}
232232

233233
return nextNode

packages/runtime-core/src/renderer.ts

+14-6
Original file line numberDiff line numberDiff line change
@@ -275,7 +275,8 @@ export const queuePostRenderEffect = __FEATURE_SUSPENSE__
275275
export const setRef = (
276276
rawRef: VNodeNormalizedRef,
277277
oldRawRef: VNodeNormalizedRef | null,
278-
parent: ComponentInternalInstance,
278+
parentComponent: ComponentInternalInstance,
279+
parentSuspense: SuspenseBoundary | null,
279280
vnode: VNode | null
280281
) => {
281282
let value: ComponentPublicInstance | RendererNode | null
@@ -306,7 +307,9 @@ export const setRef = (
306307
if (isString(oldRef)) {
307308
refs[oldRef] = null
308309
if (hasOwn(setupState, oldRef)) {
309-
setupState[oldRef] = null
310+
queuePostRenderEffect(() => {
311+
setupState[oldRef] = null
312+
}, parentSuspense)
310313
}
311314
} else if (isRef(oldRef)) {
312315
oldRef.value = null
@@ -316,12 +319,17 @@ export const setRef = (
316319
if (isString(ref)) {
317320
refs[ref] = value
318321
if (hasOwn(setupState, ref)) {
319-
setupState[ref] = value
322+
queuePostRenderEffect(() => {
323+
setupState[ref] = value
324+
}, parentSuspense)
320325
}
321326
} else if (isRef(ref)) {
322327
ref.value = value
323328
} else if (isFunction(ref)) {
324-
callWithErrorHandling(ref, parent, ErrorCodes.FUNCTION_REF, [value, refs])
329+
callWithErrorHandling(ref, parentComponent, ErrorCodes.FUNCTION_REF, [
330+
value,
331+
refs
332+
])
325333
} else if (__DEV__) {
326334
warn('Invalid template ref type:', value, `(${typeof value})`)
327335
}
@@ -497,7 +505,7 @@ function baseCreateRenderer(
497505

498506
// set ref
499507
if (ref != null && parentComponent) {
500-
setRef(ref, n1 && n1.ref, parentComponent, n2)
508+
setRef(ref, n1 && n1.ref, parentComponent, parentSuspense, n2)
501509
}
502510
}
503511

@@ -1868,7 +1876,7 @@ function baseCreateRenderer(
18681876
} = vnode
18691877
// unset ref
18701878
if (ref != null && parentComponent) {
1871-
setRef(ref, null, parentComponent, null)
1879+
setRef(ref, null, parentComponent, parentSuspense, null)
18721880
}
18731881

18741882
if (shapeFlag & ShapeFlags.COMPONENT_SHOULD_KEEP_ALIVE) {

0 commit comments

Comments
 (0)