Skip to content

Commit

Permalink
fix(portal): portal should always remove its children when unmounted
Browse files Browse the repository at this point in the history
  • Loading branch information
yyx990803 committed Mar 25, 2020
1 parent cb31eb4 commit 16cd8ee
Show file tree
Hide file tree
Showing 5 changed files with 48 additions and 3 deletions.
7 changes: 5 additions & 2 deletions packages/compiler-core/src/transforms/vIf.ts
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,8 @@ import {
CREATE_BLOCK,
FRAGMENT,
CREATE_COMMENT,
OPEN_BLOCK
OPEN_BLOCK,
PORTAL
} from '../runtimeHelpers'
import { injectProp } from '../utils'
import { PatchFlags, PatchFlagNames } from '@vue/shared'
Expand Down Expand Up @@ -216,7 +217,9 @@ function createChildrenCodegenNode(
vnodeCall.type === NodeTypes.VNODE_CALL &&
// component vnodes are always tracked and its children are
// compiled into slots so no need to make it a block
(firstChild as ElementNode).tagType !== ElementTypes.COMPONENT
((firstChild as ElementNode).tagType !== ElementTypes.COMPONENT ||
// portal has component type but isn't always tracked
vnodeCall.tag === PORTAL)
) {
vnodeCall.isBlock = true
helper(OPEN_BLOCK)
Expand Down
17 changes: 17 additions & 0 deletions packages/runtime-core/__tests__/components/Portal.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -76,4 +76,21 @@ describe('renderer: portal', () => {

expect(serializeInner(target)).toMatchSnapshot()
})

test('should remove children when unmounted', () => {
const target = nodeOps.createElement('div')
const root = nodeOps.createElement('div')

const Comp = defineComponent(() => () => [
h(Portal, { target }, h('div', 'teleported')),
h('div', 'root')
])
render(h(Comp), root)
expect(serializeInner(target)).toMatchInlineSnapshot(
`"<div>teleported</div>"`
)

render(null, root)
expect(serializeInner(target)).toBe('')
})
})
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP

exports[`renderer: portal should remove children when unmounted 1`] = `"<div>teleported</div>"`;

exports[`renderer: portal should update children 1`] = `"<div>teleported</div>"`;

exports[`renderer: portal should update children 2`] = `""`;
Expand Down
14 changes: 14 additions & 0 deletions packages/runtime-core/src/components/Portal.ts
Original file line number Diff line number Diff line change
Expand Up @@ -113,6 +113,20 @@ export const PortalImpl = {
}
}
}
},

remove(
vnode: VNode,
{ r: remove, o: { setElementText } }: RendererInternals
) {
const { target, shapeFlag, children } = vnode
if (shapeFlag & ShapeFlags.TEXT_CHILDREN) {
setElementText(target!, '')
} else if (shapeFlag & ShapeFlags.ARRAY_CHILDREN) {
for (let i = 0; i < (children as VNode[]).length; i++) {
remove((children as VNode[])[i])
}
}
}
}

Expand Down
11 changes: 10 additions & 1 deletion packages/runtime-core/src/renderer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -139,6 +139,7 @@ export interface RendererInternals<
> {
p: PatchFn
um: UnmountFn
r: RemoveFn
m: MoveFn
mt: MountComponentFn
mc: MountChildrenFn
Expand Down Expand Up @@ -210,6 +211,8 @@ type UnmountFn = (
doRemove?: boolean
) => void

type RemoveFn = (vnode: VNode) => void

type UnmountChildrenFn = (
children: VNode[],
parentComponent: ComponentInternalInstance | null,
Expand Down Expand Up @@ -1688,6 +1691,11 @@ function baseCreateRenderer(
unmountChildren(children as VNode[], parentComponent, parentSuspense)
}

// an unmounted portal should always remove its children
if (shapeFlag & ShapeFlags.PORTAL) {
;(vnode.type as typeof PortalImpl).remove(vnode, internals)
}

if (doRemove) {
remove(vnode)
}
Expand All @@ -1702,7 +1710,7 @@ function baseCreateRenderer(
}
}

const remove = (vnode: VNode) => {
const remove: RemoveFn = vnode => {
const { type, el, anchor, transition } = vnode
if (type === Fragment) {
removeFragment(el!, anchor!)
Expand Down Expand Up @@ -1888,6 +1896,7 @@ function baseCreateRenderer(
p: patch,
um: unmount,
m: move,
r: remove,
mt: mountComponent,
mc: mountChildren,
pc: patchChildren,
Expand Down

0 comments on commit 16cd8ee

Please sign in to comment.