Skip to content

Commit 7562e72

Browse files
authored
fix(runtime-core): fix async component ref handling (#3191)
fix #3188
1 parent 3f9906a commit 7562e72

File tree

2 files changed

+53
-2
lines changed

2 files changed

+53
-2
lines changed

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

+48-1
Original file line numberDiff line numberDiff line change
@@ -662,7 +662,7 @@ describe('api: defineAsyncComponent', () => {
662662
})
663663
)
664664

665-
const fooRef = ref()
665+
const fooRef = ref<any>(null)
666666
const toggle = ref(true)
667667
const root = nodeOps.createElement('div')
668668
createApp({
@@ -697,4 +697,51 @@ describe('api: defineAsyncComponent', () => {
697697
expect(serializeInner(root)).toBe('resolved')
698698
expect(fooRef.value.id).toBe('foo')
699699
})
700+
701+
// #3188
702+
test('the forwarded template ref should always exist when doing multi patching', async () => {
703+
let resolve: (comp: Component) => void
704+
const Foo = defineAsyncComponent(
705+
() =>
706+
new Promise(r => {
707+
resolve = r as any
708+
})
709+
)
710+
711+
const fooRef = ref<any>(null)
712+
const toggle = ref(true)
713+
const updater = ref(0)
714+
715+
const root = nodeOps.createElement('div')
716+
createApp({
717+
render: () =>
718+
toggle.value ? [h(Foo, { ref: fooRef }), updater.value] : null
719+
}).mount(root)
720+
721+
expect(serializeInner(root)).toBe('<!---->0')
722+
expect(fooRef.value).toBe(null)
723+
724+
resolve!({
725+
data() {
726+
return {
727+
id: 'foo'
728+
}
729+
},
730+
render: () => 'resolved'
731+
})
732+
733+
await timeout()
734+
expect(serializeInner(root)).toBe('resolved0')
735+
expect(fooRef.value.id).toBe('foo')
736+
737+
updater.value++
738+
await nextTick()
739+
expect(serializeInner(root)).toBe('resolved1')
740+
expect(fooRef.value.id).toBe('foo')
741+
742+
toggle.value = false
743+
await nextTick()
744+
expect(serializeInner(root)).toBe('<!---->')
745+
expect(fooRef.value).toBe(null)
746+
})
700747
})

packages/runtime-core/src/renderer.ts

+5-1
Original file line numberDiff line numberDiff line change
@@ -313,9 +313,13 @@ export const setRef = (
313313
}
314314

315315
let value: ComponentPublicInstance | RendererNode | Record<string, any> | null
316-
if (!vnode || isAsyncWrapper(vnode)) {
316+
if (!vnode) {
317+
// means unmount
317318
value = null
318319
} else {
320+
// when mounting async components, nothing needs to be done,
321+
// because the template ref is forwarded to inner component
322+
if (isAsyncWrapper(vnode)) return
319323
if (vnode.shapeFlag & ShapeFlags.STATEFUL_COMPONENT) {
320324
value = vnode.component!.exposed || vnode.component!.proxy
321325
} else {

0 commit comments

Comments
 (0)