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,50 +1508,15 @@ 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 (anchor != null) hostRemove(anchor)
if (
transition != null &&
!transition.persisted &&
transition.afterLeave
) {
transition.afterLeave()
}
}
if (
vnode.shapeFlag & ShapeFlags.ELEMENT &&
transition != null &&
!transition.persisted
) {
const { leave, delayLeave } = transition
const performLeave = () => leave(el!, remove)
if (delayLeave) {
delayLeave(vnode.el!, remove, performLeave)
} else {
performLeave()
}
} else {
remove()
}
} }
if (props != null && props.onVnodeUnmounted != null) { if (props != null && props.onVnodeUnmounted != null) {
@ -1571,6 +1526,47 @@ export function createRenderer<
} }
} }
function remove(vnode: HostVNode) {
const { type, el, anchor, children, transition } = vnode
const performRemove = () => {
hostRemove(el!)
if (anchor != null) hostRemove(anchor)
if (
transition != null &&
!transition.persisted &&
transition.afterLeave
) {
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 {
performLeave()
}
} else {
performRemove()
}
}
function removeChildren(children: HostVNode[]) {
for (let i = 0; i < children.length; i++) {
remove(children[i])
}
}
function unmountComponent( function unmountComponent(
instance: ComponentInternalInstance, instance: ComponentInternalInstance,
parentSuspense: HostSuspenseBoundary | null, parentSuspense: HostSuspenseBoundary | null,