From fa5390fb6fae4a4f7f6ffa2c0823fd3c48099d41 Mon Sep 17 00:00:00 2001 From: Evan You Date: Fri, 13 Dec 2019 10:31:40 -0500 Subject: [PATCH] fix(fragment): properly remove compiler generated fragments --- .../__tests__/rendererFragment.spec.ts | 4 + packages/runtime-core/src/renderer.ts | 94 +++++++++---------- 2 files changed, 49 insertions(+), 49 deletions(-) diff --git a/packages/runtime-core/__tests__/rendererFragment.spec.ts b/packages/runtime-core/__tests__/rendererFragment.spec.ts index 7c4be2b3f5..dd3a27b727 100644 --- a/packages/runtime-core/__tests__/rendererFragment.spec.ts +++ b/packages/runtime-core/__tests__/rendererFragment.spec.ts @@ -260,5 +260,9 @@ describe('renderer: fragment', () => { { type: NodeOpTypes.INSERT, targetNode: { type: 'element' } }, { type: NodeOpTypes.INSERT, targetNode: { type: 'comment' } } ]) + + // should properly remove nested fragments + render(null, root) + expect(serializeInner(root)).toBe(``) }) }) diff --git a/packages/runtime-core/src/renderer.ts b/packages/runtime-core/src/renderer.ts index f4f81d54d5..ba981f4f92 100644 --- a/packages/runtime-core/src/renderer.ts +++ b/packages/runtime-core/src/renderer.ts @@ -1483,17 +1483,7 @@ export function createRenderer< parentSuspense: HostSuspenseBoundary | null, doRemove?: boolean ) { - const { - el, - props, - ref, - type, - children, - dynamicChildren, - shapeFlag, - anchor, - transition - } = vnode + const { props, ref, children, dynamicChildren, shapeFlag } = vnode // unset ref if (ref !== null && parentComponent !== null) { @@ -1518,56 +1508,62 @@ export function createRenderer< invokeDirectiveHook(props.onVnodeBeforeUnmount, parentComponent, vnode) } - const shouldRemoveChildren = type === Fragment && doRemove if (dynamicChildren != null) { - unmountChildren( - dynamicChildren, - parentComponent, - parentSuspense, - shouldRemoveChildren - ) + // fast path for block nodes: only need to unmount dynamic children. + unmountChildren(dynamicChildren, parentComponent, parentSuspense) } else if (shapeFlag & ShapeFlags.ARRAY_CHILDREN) { - unmountChildren( - children as HostVNode[], - parentComponent, - parentSuspense, - shouldRemoveChildren - ) + unmountChildren(children as HostVNode[], parentComponent, parentSuspense) } if (doRemove) { - const remove = () => { - hostRemove(vnode.el!) - if (anchor != null) hostRemove(anchor) - if ( - transition != null && - !transition.persisted && - transition.afterLeave - ) { - transition.afterLeave() - } - } + remove(vnode) + } + + if (props != null && props.onVnodeUnmounted != null) { + queuePostRenderEffect(() => { + invokeDirectiveHook(props.onVnodeUnmounted!, parentComponent, vnode) + }, parentSuspense) + } + } + + function remove(vnode: HostVNode) { + const { type, el, anchor, children, transition } = vnode + const performRemove = () => { + hostRemove(el!) + if (anchor != null) hostRemove(anchor) if ( - vnode.shapeFlag & ShapeFlags.ELEMENT && transition != null && - !transition.persisted + !transition.persisted && + transition.afterLeave ) { - const { leave, delayLeave } = transition - const performLeave = () => leave(el!, remove) - if (delayLeave) { - delayLeave(vnode.el!, remove, performLeave) - } else { - performLeave() - } + transition.afterLeave() + } + } + if (type === Fragment) { + performRemove() + removeChildren(children as HostVNode[]) + return + } + if ( + vnode.shapeFlag & ShapeFlags.ELEMENT && + transition != null && + !transition.persisted + ) { + const { leave, delayLeave } = transition + const performLeave = () => leave(el!, performRemove) + if (delayLeave) { + delayLeave(vnode.el!, performRemove, performLeave) } else { - remove() + performLeave() } + } else { + performRemove() } + } - if (props != null && props.onVnodeUnmounted != null) { - queuePostRenderEffect(() => { - invokeDirectiveHook(props.onVnodeUnmounted!, parentComponent, vnode) - }, parentSuspense) + function removeChildren(children: HostVNode[]) { + for (let i = 0; i < children.length; i++) { + remove(children[i]) } } -- 2.47.3