From 2925c36be2e5b81020060f98ba9c86face8349a1 Mon Sep 17 00:00:00 2001 From: linzhe141 <1572213544@qq.com> Date: Thu, 15 Aug 2024 11:29:37 +0800 Subject: [PATCH 1/5] fix(runtime-core): fix nonHydratedAsyncRoot update --- packages/runtime-core/src/renderer.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/runtime-core/src/renderer.ts b/packages/runtime-core/src/renderer.ts index 3d1cc6849c7..a543223cad2 100644 --- a/packages/runtime-core/src/renderer.ts +++ b/packages/runtime-core/src/renderer.ts @@ -1438,7 +1438,7 @@ function baseCreateRenderer( nonHydratedAsyncRoot.asyncDep!.then(() => { // the instance may be destroyed during the time period if (!instance.isUnmounted) { - componentUpdateFn() + instance.update() } }) return From 8b7340bb37917347f979ef74f15853ff5aedffd1 Mon Sep 17 00:00:00 2001 From: linzhe141 <1572213544@qq.com> Date: Thu, 15 Aug 2024 13:36:44 +0800 Subject: [PATCH 2/5] chore: update --- packages/runtime-core/src/renderer.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/runtime-core/src/renderer.ts b/packages/runtime-core/src/renderer.ts index a543223cad2..1e7b3572725 100644 --- a/packages/runtime-core/src/renderer.ts +++ b/packages/runtime-core/src/renderer.ts @@ -1438,7 +1438,7 @@ function baseCreateRenderer( nonHydratedAsyncRoot.asyncDep!.then(() => { // the instance may be destroyed during the time period if (!instance.isUnmounted) { - instance.update() + update() } }) return From 864fa327e19af15c453762a1dc685b293a17cf84 Mon Sep 17 00:00:00 2001 From: linzhe141 <1572213544@qq.com> Date: Thu, 15 Aug 2024 15:03:25 +0800 Subject: [PATCH 3/5] chore: update --- packages/runtime-core/src/renderer.ts | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/packages/runtime-core/src/renderer.ts b/packages/runtime-core/src/renderer.ts index 1e7b3572725..85497f1412f 100644 --- a/packages/runtime-core/src/renderer.ts +++ b/packages/runtime-core/src/renderer.ts @@ -1207,6 +1207,9 @@ function baseCreateRenderer( // setup() is async. This component relies on async logic to be resolved // before proceeding if (__FEATURE_SUSPENSE__ && instance.asyncDep) { + if (parentSuspense) { + parentSuspense.pendingBranch = instance.vnode + } parentSuspense && parentSuspense.registerDep(instance, setupRenderEffect, optimized) @@ -1438,7 +1441,7 @@ function baseCreateRenderer( nonHydratedAsyncRoot.asyncDep!.then(() => { // the instance may be destroyed during the time period if (!instance.isUnmounted) { - update() + componentUpdateFn() } }) return From bbcb220f466bb7958858834ca671e9eb62d100d6 Mon Sep 17 00:00:00 2001 From: linzhe Date: Thu, 15 Aug 2024 19:28:48 +0800 Subject: [PATCH 4/5] chore: update test --- .../__tests__/components/Suspense.spec.ts | 75 +++++++++++++++++++ packages/runtime-core/src/renderer.ts | 9 +-- 2 files changed, 78 insertions(+), 6 deletions(-) diff --git a/packages/runtime-core/__tests__/components/Suspense.spec.ts b/packages/runtime-core/__tests__/components/Suspense.spec.ts index 65e801de277..ad5b9a6d880 100644 --- a/packages/runtime-core/__tests__/components/Suspense.spec.ts +++ b/packages/runtime-core/__tests__/components/Suspense.spec.ts @@ -15,6 +15,7 @@ import { onErrorCaptured, onMounted, onUnmounted, + onUpdated, ref, render, resolveDynamicComponent, @@ -2161,6 +2162,80 @@ describe('Suspense', () => { await Promise.all(deps) }) + test('Suspense & Component with `component is`', async () => { + const arr: boolean[] = [] + const Child = { + props: ['loading'], + async setup(props: any) { + onUpdated(() => { + arr.push(props.loading) + }) + await 1 + return () => { + const loading = props.loading + return h('div', null, loading ? '1' : '2') + } + }, + } + + const Parent = defineComponent({ + setup() { + const loading = ref(false) + const delay = (delayInms: any) => { + return new Promise(resolve => setTimeout(resolve, delayInms)) + } + onMounted(async () => { + loading.value = true + await delay(1000) + loading.value = false + await nextTick() + expect(arr).toEqual([true, false]) + }) + return () => { + return h(Child, { loading: loading.value }) + } + }, + }) + + const RouterView = { + props: { + name: { type: Object }, + }, + setup(props: any) { + return () => { + const name = props.name + return h(name) + } + }, + } + const App = { + setup() { + const Dummy = { + setup() { + return () => { + return h('div', null, 'dummy') + } + }, + } + + const flag: any = shallowRef(Dummy) + + onMounted(() => { + flag.value = Parent + }) + return () => { + return h(Suspense, null, { + default: () => h(RouterView, { name: flag.value }), + }) + } + }, + } + + const root: any = nodeOps.createElement('div') + + render(h(App), root) + }) + describe('warnings', () => { // base function to check if a combination of slots warns or not function baseCheckWarn( diff --git a/packages/runtime-core/src/renderer.ts b/packages/runtime-core/src/renderer.ts index 85497f1412f..f00e489ace1 100644 --- a/packages/runtime-core/src/renderer.ts +++ b/packages/runtime-core/src/renderer.ts @@ -1207,9 +1207,6 @@ function baseCreateRenderer( // setup() is async. This component relies on async logic to be resolved // before proceeding if (__FEATURE_SUSPENSE__ && instance.asyncDep) { - if (parentSuspense) { - parentSuspense.pendingBranch = instance.vnode - } parentSuspense && parentSuspense.registerDep(instance, setupRenderEffect, optimized) @@ -1440,9 +1437,9 @@ function baseCreateRenderer( // and continue the rest of operations once the deps are resolved nonHydratedAsyncRoot.asyncDep!.then(() => { // the instance may be destroyed during the time period - if (!instance.isUnmounted) { - componentUpdateFn() - } + queuePostRenderEffect(() => { + if (!instance.isUnmounted) update() + }, parentSuspense) }) return } From 2bb0ab69167112dcadbfa9e28d87bc6652b78ad2 Mon Sep 17 00:00:00 2001 From: edison Date: Thu, 15 Aug 2024 20:08:10 +0800 Subject: [PATCH 5/5] update test case name --- packages/runtime-core/__tests__/components/Suspense.spec.ts | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/packages/runtime-core/__tests__/components/Suspense.spec.ts b/packages/runtime-core/__tests__/components/Suspense.spec.ts index ad5b9a6d880..354e33b8cfb 100644 --- a/packages/runtime-core/__tests__/components/Suspense.spec.ts +++ b/packages/runtime-core/__tests__/components/Suspense.spec.ts @@ -2162,7 +2162,8 @@ describe('Suspense', () => { await Promise.all(deps) }) - test('Suspense & Component with `component is`', async () => { + //#11617 + test('update async component before resolve then update again', async () => { const arr: boolean[] = [] const Child = { props: ['loading'],