Skip to content

Commit

Permalink
fix(runtime-core): fix async component ref handling (#3191)
Browse files Browse the repository at this point in the history
fix #3188
  • Loading branch information
HcySunYang committed Mar 1, 2021
1 parent 3f9906a commit 7562e72
Show file tree
Hide file tree
Showing 2 changed files with 53 additions and 2 deletions.
49 changes: 48 additions & 1 deletion packages/runtime-core/__tests__/apiAsyncComponent.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -662,7 +662,7 @@ describe('api: defineAsyncComponent', () => {
})
)

const fooRef = ref()
const fooRef = ref<any>(null)
const toggle = ref(true)
const root = nodeOps.createElement('div')
createApp({
Expand Down Expand Up @@ -697,4 +697,51 @@ describe('api: defineAsyncComponent', () => {
expect(serializeInner(root)).toBe('resolved')
expect(fooRef.value.id).toBe('foo')
})

// #3188
test('the forwarded template ref should always exist when doing multi patching', async () => {
let resolve: (comp: Component) => void
const Foo = defineAsyncComponent(
() =>
new Promise(r => {
resolve = r as any
})
)

const fooRef = ref<any>(null)
const toggle = ref(true)
const updater = ref(0)

const root = nodeOps.createElement('div')
createApp({
render: () =>
toggle.value ? [h(Foo, { ref: fooRef }), updater.value] : null
}).mount(root)

expect(serializeInner(root)).toBe('<!---->0')
expect(fooRef.value).toBe(null)

resolve!({
data() {
return {
id: 'foo'
}
},
render: () => 'resolved'
})

await timeout()
expect(serializeInner(root)).toBe('resolved0')
expect(fooRef.value.id).toBe('foo')

updater.value++
await nextTick()
expect(serializeInner(root)).toBe('resolved1')
expect(fooRef.value.id).toBe('foo')

toggle.value = false
await nextTick()
expect(serializeInner(root)).toBe('<!---->')
expect(fooRef.value).toBe(null)
})
})
6 changes: 5 additions & 1 deletion packages/runtime-core/src/renderer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -313,9 +313,13 @@ export const setRef = (
}

let value: ComponentPublicInstance | RendererNode | Record<string, any> | null
if (!vnode || isAsyncWrapper(vnode)) {
if (!vnode) {
// means unmount
value = null
} else {
// when mounting async components, nothing needs to be done,
// because the template ref is forwarded to inner component
if (isAsyncWrapper(vnode)) return
if (vnode.shapeFlag & ShapeFlags.STATEFUL_COMPONENT) {
value = vnode.component!.exposed || vnode.component!.proxy
} else {
Expand Down

0 comments on commit 7562e72

Please sign in to comment.