From 58cf2365e44b487e795687030558190970589de9 Mon Sep 17 00:00:00 2001 From: daiwei Date: Mon, 30 Sep 2024 09:42:40 +0800 Subject: [PATCH 1/2] fix(templateRef): delay setting the ref value if wrapped in Suspense --- packages/runtime-core/src/rendererTemplateRef.ts | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/packages/runtime-core/src/rendererTemplateRef.ts b/packages/runtime-core/src/rendererTemplateRef.ts index 1ffe3035794..c6da0b14a60 100644 --- a/packages/runtime-core/src/rendererTemplateRef.ts +++ b/packages/runtime-core/src/rendererTemplateRef.ts @@ -28,6 +28,13 @@ export function setRef( vnode: VNode, isUnmount = false, ): void { + if (parentSuspense) { + queuePostRenderEffect(() => { + setRef(rawRef, oldRawRef, null, vnode, isUnmount) + }, parentSuspense) + return + } + if (isArray(rawRef)) { rawRef.forEach((r, i) => setRef( From 754c3ba9d67bda9346107f26a57c6bb544eb97ba Mon Sep 17 00:00:00 2001 From: daiwei Date: Mon, 30 Sep 2024 11:03:48 +0800 Subject: [PATCH 2/2] test: add test case --- .../__tests__/rendererTemplateRef.spec.ts | 36 +++++++++++++++++++ 1 file changed, 36 insertions(+) diff --git a/packages/runtime-core/__tests__/rendererTemplateRef.spec.ts b/packages/runtime-core/__tests__/rendererTemplateRef.spec.ts index 799108dca8a..62aebd1a995 100644 --- a/packages/runtime-core/__tests__/rendererTemplateRef.spec.ts +++ b/packages/runtime-core/__tests__/rendererTemplateRef.spec.ts @@ -1,4 +1,5 @@ import { + Suspense, defineComponent, h, nextTick, @@ -537,4 +538,39 @@ describe('api: template refs', () => { '
[object Object],[object Object]
  • 2
  • 3
', ) }) + + it('with async component', async () => { + const deps: Promise[] = [] + const spy = vi.fn() + + const AsyncChild = defineComponent({ + async setup(_, { expose }) { + const p = new Promise(r => setTimeout(r, 1)) + deps.push(p.then(() => Promise.resolve())) + await p + expose({ foo: spy }) + return () => h('div', 'child') + }, + }) + + const childRef = ref(null) + const App = { + setup() { + return { refKey: childRef } + }, + render() { + return h(Suspense, null, { default: h(AsyncChild, { ref: 'refKey' }) }) + }, + } + + const root = nodeOps.createElement('div') + render(h(App), root) + + await Promise.all(deps) + await nextTick() + + expect((childRef.value as any).foo).toBe(spy) + ;(childRef.value as any).foo() + expect(spy).toBeCalledTimes(1) + }) })