From 8b85aaeea9b2ed343e2ae19958abbd9e5d223a77 Mon Sep 17 00:00:00 2001 From: underfin <2218301630@qq.com> Date: Sat, 2 May 2020 04:20:16 +0800 Subject: [PATCH] fix(runtime-core): should call Suspense fallback unmount hook (#1061) fix #1059 --- .../__tests__/components/Suspense.spec.ts | 53 ++++++++++++++++++- packages/runtime-core/src/renderer.ts | 4 +- 2 files changed, 54 insertions(+), 3 deletions(-) diff --git a/packages/runtime-core/__tests__/components/Suspense.spec.ts b/packages/runtime-core/__tests__/components/Suspense.spec.ts index cb8ece4873e..8c5eecac56d 100644 --- a/packages/runtime-core/__tests__/components/Suspense.spec.ts +++ b/packages/runtime-core/__tests__/components/Suspense.spec.ts @@ -221,6 +221,57 @@ describe('Suspense', () => { ]) }) + // #1059 + test('mounted/updated hooks & fallback component', async () => { + const deps: Promise[] = [] + const calls: string[] = [] + const toggle = ref(true) + + const Async = { + async setup() { + const p = new Promise(r => setTimeout(r, 1)) + // extra tick needed for Node 12+ + deps.push(p.then(() => Promise.resolve())) + + await p + return () => h('div', 'async') + } + } + + const Fallback = { + setup() { + onMounted(() => { + calls.push('mounted') + }) + + onUnmounted(() => { + calls.push('unmounted') + }) + return () => h('div', 'fallback') + } + } + + const Comp = { + setup() { + return () => + h(Suspense, null, { + default: toggle.value ? h(Async) : null, + fallback: h(Fallback) + }) + } + } + + const root = nodeOps.createElement('div') + render(h(Comp), root) + expect(serializeInner(root)).toBe(`
fallback
`) + expect(calls).toEqual([`mounted`]) + + await Promise.all(deps) + await nextTick() + expect(serializeInner(root)).toBe(`
async
`) + expect(calls).toEqual([`mounted`, `unmounted`]) + }) + test('content update before suspense resolve', async () => { const Async = defineAsyncComponent({ props: { msg: String }, @@ -316,7 +367,7 @@ describe('Suspense', () => { await nextTick() expect(serializeInner(root)).toBe(``) // should discard effects (except for immediate ones) - expect(calls).toEqual(['immediate effect']) + expect(calls).toEqual(['immediate effect', 'watch callback', 'unmounted']) }) test('unmount suspense after resolve', async () => { diff --git a/packages/runtime-core/src/renderer.ts b/packages/runtime-core/src/renderer.ts index 4152b7ded55..de213968855 100644 --- a/packages/runtime-core/src/renderer.ts +++ b/packages/runtime-core/src/renderer.ts @@ -1856,9 +1856,9 @@ function baseCreateRenderer( ) { queuePostRenderEffect(da, parentSuspense) } - queuePostFlushCb(() => { + queuePostRenderEffect(() => { instance.isUnmounted = true - }) + }, parentSuspense) // A component with async dep inside a pending suspense is unmounted before // its async dep resolves. This should remove the dep from the suspense, and