fallback: [h('div'), h('div')],
})
})
+
+ // #13559
+ test('renders multiple async components in Suspense with v-for and updates on items change', async () => {
+ const CompAsyncSetup = defineAsyncComponent({
+ props: ['item'],
+ render(ctx: any) {
+ return h('div', ctx.item.name)
+ },
+ })
+
+ const items = ref([
+ { id: 1, name: '111' },
+ { id: 2, name: '222' },
+ { id: 3, name: '333' },
+ ])
+
+ const Comp = {
+ setup() {
+ return () =>
+ h(Suspense, null, {
+ default: () =>
+ h(
+ Fragment,
+ null,
+ items.value.map(item =>
+ h(CompAsyncSetup, { item, key: item.id }),
+ ),
+ ),
+ })
+ },
+ }
+
+ const root = nodeOps.createElement('div')
+ render(h(Comp), root)
+ await nextTick()
+ await Promise.all(deps)
+
+ expect(serializeInner(root)).toBe(
+ `<div>111</div><div>222</div><div>333</div>`,
+ )
+
+ items.value = [
+ { id: 4, name: '444' },
+ { id: 5, name: '555' },
+ { id: 6, name: '666' },
+ ]
+ await nextTick()
+ await Promise.all(deps)
+ expect(serializeInner(root)).toBe(
+ `<div>444</div><div>555</div><div>666</div>`,
+ )
+ })
})
})
if (!initialVNode.el) {
const placeholder = (instance.subTree = createVNode(Comment))
processCommentNode(null, placeholder, container!, anchor)
+ initialVNode.placeholder = placeholder.el
}
} else {
setupRenderEffect(
for (i = toBePatched - 1; i >= 0; i--) {
const nextIndex = s2 + i
const nextChild = c2[nextIndex] as VNode
+ const anchorVNode = c2[nextIndex + 1] as VNode
const anchor =
- nextIndex + 1 < l2 ? (c2[nextIndex + 1] as VNode).el : parentAnchor
+ nextIndex + 1 < l2
+ ? // #13559, fallback to el placeholder for unresolved async component
+ anchorVNode.el || anchorVNode.placeholder
+ : parentAnchor
if (newIndexToOldIndexMap[i] === 0) {
// mount new
patch(
// DOM
el: HostNode | null
+ placeholder: HostNode | null // async component el placeholder
anchor: HostNode | null // fragment anchor
target: HostElement | null // teleport target
targetStart: HostNode | null // teleport target start anchor
suspense: vnode.suspense,
ssContent: vnode.ssContent && cloneVNode(vnode.ssContent),
ssFallback: vnode.ssFallback && cloneVNode(vnode.ssFallback),
+ placeholder: vnode.placeholder,
+
el: vnode.el,
anchor: vnode.anchor,
ctx: vnode.ctx,