Skip to content

Commit e71c26c

Browse files
authored
fix(runtime-core): properly handle async component update before resolve (#11619)
close #11617
1 parent 57866b5 commit e71c26c

File tree

2 files changed

+79
-3
lines changed

2 files changed

+79
-3
lines changed

packages/runtime-core/__tests__/components/Suspense.spec.ts

Lines changed: 76 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ import {
1515
onErrorCaptured,
1616
onMounted,
1717
onUnmounted,
18+
onUpdated,
1819
ref,
1920
render,
2021
renderList,
@@ -2164,6 +2165,81 @@ describe('Suspense', () => {
21642165
await Promise.all(deps)
21652166
})
21662167

2168+
//#11617
2169+
test('update async component before resolve then update again', async () => {
2170+
const arr: boolean[] = []
2171+
const Child = {
2172+
props: ['loading'],
2173+
async setup(props: any) {
2174+
onUpdated(() => {
2175+
arr.push(props.loading)
2176+
})
2177+
await 1
2178+
return () => {
2179+
const loading = props.loading
2180+
return h('div', null, loading ? '1' : '2')
2181+
}
2182+
},
2183+
}
2184+
2185+
const Parent = defineComponent({
2186+
setup() {
2187+
const loading = ref(false)
2188+
const delay = (delayInms: any) => {
2189+
return new Promise(resolve => setTimeout(resolve, delayInms))
2190+
}
2191+
onMounted(async () => {
2192+
loading.value = true
2193+
await delay(1000)
2194+
loading.value = false
2195+
await nextTick()
2196+
expect(arr).toEqual([true, false])
2197+
})
2198+
return () => {
2199+
return h(Child, { loading: loading.value })
2200+
}
2201+
},
2202+
})
2203+
2204+
const RouterView = {
2205+
props: {
2206+
name: { type: Object },
2207+
},
2208+
setup(props: any) {
2209+
return () => {
2210+
const name = props.name
2211+
return h(name)
2212+
}
2213+
},
2214+
}
2215+
const App = {
2216+
setup() {
2217+
const Dummy = {
2218+
setup() {
2219+
return () => {
2220+
return h('div', null, 'dummy')
2221+
}
2222+
},
2223+
}
2224+
2225+
const flag: any = shallowRef(Dummy)
2226+
2227+
onMounted(() => {
2228+
flag.value = Parent
2229+
})
2230+
return () => {
2231+
return h(Suspense, null, {
2232+
default: () => h(RouterView, { name: flag.value }),
2233+
})
2234+
}
2235+
},
2236+
}
2237+
2238+
const root: any = nodeOps.createElement('div')
2239+
2240+
render(h(App), root)
2241+
})
2242+
21672243
// #13453
21682244
test('add new async deps during patching', async () => {
21692245
const getComponent = (type: string) => {

packages/runtime-core/src/renderer.ts

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1463,9 +1463,9 @@ function baseCreateRenderer(
14631463
// and continue the rest of operations once the deps are resolved
14641464
nonHydratedAsyncRoot.asyncDep!.then(() => {
14651465
// the instance may be destroyed during the time period
1466-
if (!instance.isUnmounted) {
1467-
componentUpdateFn()
1468-
}
1466+
queuePostRenderEffect(() => {
1467+
if (!instance.isUnmounted) update()
1468+
}, parentSuspense)
14691469
})
14701470
return
14711471
}

0 commit comments

Comments
 (0)