fix(fragment): properly remove compiler generated fragments

This commit is contained in:
Evan You 2019-12-13 10:31:40 -05:00
parent 6797e35703
commit fa5390fb6f
2 changed files with 50 additions and 50 deletions

View File

@ -260,5 +260,9 @@ describe('renderer: fragment', () => {
{ type: NodeOpTypes.INSERT, targetNode: { type: 'element' } }, { type: NodeOpTypes.INSERT, targetNode: { type: 'element' } },
{ type: NodeOpTypes.INSERT, targetNode: { type: 'comment' } } { type: NodeOpTypes.INSERT, targetNode: { type: 'comment' } }
]) ])
// should properly remove nested fragments
render(null, root)
expect(serializeInner(root)).toBe(``)
}) })
}) })

View File

@ -1483,17 +1483,7 @@ export function createRenderer<
parentSuspense: HostSuspenseBoundary | null, parentSuspense: HostSuspenseBoundary | null,
doRemove?: boolean doRemove?: boolean
) { ) {
const { const { props, ref, children, dynamicChildren, shapeFlag } = vnode
el,
props,
ref,
type,
children,
dynamicChildren,
shapeFlag,
anchor,
transition
} = vnode
// unset ref // unset ref
if (ref !== null && parentComponent !== null) { if (ref !== null && parentComponent !== null) {
@ -1518,26 +1508,28 @@ export function createRenderer<
invokeDirectiveHook(props.onVnodeBeforeUnmount, parentComponent, vnode) invokeDirectiveHook(props.onVnodeBeforeUnmount, parentComponent, vnode)
} }
const shouldRemoveChildren = type === Fragment && doRemove
if (dynamicChildren != null) { if (dynamicChildren != null) {
unmountChildren( // fast path for block nodes: only need to unmount dynamic children.
dynamicChildren, unmountChildren(dynamicChildren, parentComponent, parentSuspense)
parentComponent,
parentSuspense,
shouldRemoveChildren
)
} else if (shapeFlag & ShapeFlags.ARRAY_CHILDREN) { } else if (shapeFlag & ShapeFlags.ARRAY_CHILDREN) {
unmountChildren( unmountChildren(children as HostVNode[], parentComponent, parentSuspense)
children as HostVNode[],
parentComponent,
parentSuspense,
shouldRemoveChildren
)
} }
if (doRemove) { if (doRemove) {
const remove = () => { remove(vnode)
hostRemove(vnode.el!) }
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 (anchor != null) hostRemove(anchor)
if ( if (
transition != null && transition != null &&
@ -1547,27 +1539,31 @@ export function createRenderer<
transition.afterLeave() transition.afterLeave()
} }
} }
if (type === Fragment) {
performRemove()
removeChildren(children as HostVNode[])
return
}
if ( if (
vnode.shapeFlag & ShapeFlags.ELEMENT && vnode.shapeFlag & ShapeFlags.ELEMENT &&
transition != null && transition != null &&
!transition.persisted !transition.persisted
) { ) {
const { leave, delayLeave } = transition const { leave, delayLeave } = transition
const performLeave = () => leave(el!, remove) const performLeave = () => leave(el!, performRemove)
if (delayLeave) { if (delayLeave) {
delayLeave(vnode.el!, remove, performLeave) delayLeave(vnode.el!, performRemove, performLeave)
} else { } else {
performLeave() performLeave()
} }
} else { } else {
remove() performRemove()
} }
} }
if (props != null && props.onVnodeUnmounted != null) { function removeChildren(children: HostVNode[]) {
queuePostRenderEffect(() => { for (let i = 0; i < children.length; i++) {
invokeDirectiveHook(props.onVnodeUnmounted!, parentComponent, vnode) remove(children[i])
}, parentSuspense)
} }
} }