diff --git a/packages/runtime-core/__tests__/components/Suspense.spec.ts b/packages/runtime-core/__tests__/components/Suspense.spec.ts index 4e8da3288f1..9e05e6f80be 100644 --- a/packages/runtime-core/__tests__/components/Suspense.spec.ts +++ b/packages/runtime-core/__tests__/components/Suspense.spec.ts @@ -2395,4 +2395,67 @@ describe('Suspense', () => { expect(unmounted).toHaveBeenCalledTimes(1) }) }) + + // #14173 + test('renders multiple async components in Suspense with v-for and updates list order with HOC', async () => { + const CompAsyncSetup = defineAsyncComponent({ + props: ['item'], + render(ctx: any) { + return h('div', ctx.item.name) + }, + }) + + const CompWrapper = { + props: ['item'], + render(ctx: any) { + return h(CompAsyncSetup, { item: ctx.item }) + }, + } + + const items = ref([ + { id: 1, name: '111' }, + { id: 2, name: '222' }, + { id: 3, name: '333' }, + ]) + + const Comp = { + setup() { + return () => + h(Suspense, null, { + default: () => + h('div', [ + h( + Fragment, + null, + items.value.map(item => + h(CompWrapper, { item, key: item.id }), + ), + ), + ]), + }) + }, + } + + const root = nodeOps.createElement('div') + render(h(Comp), root) + + await nextTick() + await Promise.all(deps) + + expect(serializeInner(root)).toBe( + `
111
222
333
`, + ) + + items.value = [ + { id: 4, name: '444' }, + { id: 5, name: '555' }, + { id: 6, name: '666' }, + ] + + await nextTick() + await Promise.all(deps) + expect(serializeInner(root)).toBe( + `
444
555
666
`, + ) + }) }) diff --git a/packages/runtime-core/src/renderer.ts b/packages/runtime-core/src/renderer.ts index 192bb44474e..bac0c317741 100644 --- a/packages/runtime-core/src/renderer.ts +++ b/packages/runtime-core/src/renderer.ts @@ -1996,7 +1996,9 @@ function baseCreateRenderer( const anchor = nextIndex + 1 < l2 ? // #13559, fallback to el placeholder for unresolved async component - anchorVNode.el || anchorVNode.placeholder + anchorVNode.el || + anchorVNode.placeholder || + getSubTreeElement(anchorVNode) : parentAnchor if (newIndexToOldIndexMap[i] === 0) { // mount new @@ -2418,6 +2420,14 @@ function baseCreateRenderer( ) } + const getSubTreeElement = (vnode: VNode): RendererNode | null => { + let current = vnode + while (current.component) { + current = current.component.subTree + } + return current.el || current.placeholder + } + return { render, hydrate,