From 123738727a0af54fd632bf838dc3aa024722ee41 Mon Sep 17 00:00:00 2001 From: Evan You Date: Tue, 24 Mar 2020 10:28:00 -0400 Subject: [PATCH] fix(keep-alive): should update re-activated component with latest props --- .../__tests__/components/KeepAlive.spec.ts | 27 ++++++++++++++ .../runtime-core/src/components/KeepAlive.ts | 36 +++++++++++++------ packages/runtime-core/src/renderer.ts | 4 ++- 3 files changed, 55 insertions(+), 12 deletions(-) diff --git a/packages/runtime-core/__tests__/components/KeepAlive.spec.ts b/packages/runtime-core/__tests__/components/KeepAlive.spec.ts index 9bcec22e..be17b077 100644 --- a/packages/runtime-core/__tests__/components/KeepAlive.spec.ts +++ b/packages/runtime-core/__tests__/components/KeepAlive.spec.ts @@ -531,5 +531,32 @@ describe('KeepAlive', () => { await nextTick() expect(Foo.unmounted).not.toHaveBeenCalled() }) + + test('should update re-activated component if props have changed', async () => { + const Foo = (props: { n: number }) => props.n + + const toggle = ref(true) + const n = ref(0) + + const App = { + setup() { + return () => + h(KeepAlive, () => (toggle.value ? h(Foo, { n: n.value }) : null)) + } + } + + render(h(App), root) + expect(serializeInner(root)).toBe(`0`) + + toggle.value = false + await nextTick() + expect(serializeInner(root)).toBe(``) + + n.value++ + await nextTick() + toggle.value = true + await nextTick() + expect(serializeInner(root)).toBe(`1`) + }) }) }) diff --git a/packages/runtime-core/src/components/KeepAlive.ts b/packages/runtime-core/src/components/KeepAlive.ts index c66fd50d..c2506309 100644 --- a/packages/runtime-core/src/components/KeepAlive.ts +++ b/packages/runtime-core/src/components/KeepAlive.ts @@ -41,7 +41,9 @@ export interface KeepAliveSink { activate: ( vnode: VNode, container: RendererElement, - anchor: RendererNode | null + anchor: RendererNode | null, + isSVG: boolean, + optimized: boolean ) => void deactivate: (vnode: VNode) => void } @@ -78,6 +80,7 @@ const KeepAliveImpl = { const sink = instance.sink as KeepAliveSink const { renderer: { + p: patch, m: move, um: _unmount, o: { createElement } @@ -86,13 +89,24 @@ const KeepAliveImpl = { } = sink const storageContainer = createElement('div') - sink.activate = (vnode, container, anchor) => { + sink.activate = (vnode, container, anchor, isSVG, optimized) => { + const child = vnode.component! move(vnode, container, anchor, MoveType.ENTER, parentSuspense) + // in case props have changed + patch( + child.vnode, + vnode, + container, + anchor, + instance, + parentSuspense, + isSVG, + optimized + ) queuePostRenderEffect(() => { - const component = vnode.component! - component.isDeactivated = false - if (component.a) { - invokeHooks(component.a) + child.isDeactivated = false + if (child.a) { + invokeHooks(child.a) } }, parentSuspense) } @@ -181,7 +195,7 @@ const KeepAliveImpl = { } const key = vnode.key == null ? comp : vnode.key - const cached = cache.get(key) + const cachedVNode = cache.get(key) // clone vnode if it's reused because we are going to mutate it if (vnode.el) { @@ -189,11 +203,11 @@ const KeepAliveImpl = { } cache.set(key, vnode) - if (cached) { + if (cachedVNode) { // copy over mounted state - vnode.el = cached.el - vnode.anchor = cached.anchor - vnode.component = cached.component + vnode.el = cachedVNode.el + vnode.anchor = cachedVNode.anchor + vnode.component = cachedVNode.component if (vnode.transition) { // recursively update transition hooks on subTree setTransitionHooks(vnode, vnode.transition!) diff --git a/packages/runtime-core/src/renderer.ts b/packages/runtime-core/src/renderer.ts index 0385a6dc..e80a4976 100644 --- a/packages/runtime-core/src/renderer.ts +++ b/packages/runtime-core/src/renderer.ts @@ -946,7 +946,9 @@ function baseCreateRenderer( ;(parentComponent!.sink as KeepAliveSink).activate( n2, container, - anchor + anchor, + isSVG, + optimized ) } else { mountComponent(