wip: pass suspense down as argument

This commit is contained in:
Evan You 2019-09-10 12:08:30 -04:00
parent 0fff3a6ef5
commit 2677c91aba
3 changed files with 181 additions and 52 deletions

View File

@ -122,4 +122,6 @@ describe('renderer: suspense', () => {
test.todo('nested suspense') test.todo('nested suspense')
test.todo('error handling') test.todo('error handling')
test.todo('portal inside suspense')
}) })

View File

@ -13,8 +13,7 @@ import {
ComponentInternalInstance, ComponentInternalInstance,
createComponentInstance, createComponentInstance,
setupStatefulComponent, setupStatefulComponent,
handleSetupResult, handleSetupResult
setCurrentInstance
} from './component' } from './component'
import { import {
renderComponentRoot, renderComponentRoot,
@ -49,7 +48,6 @@ import {
createSuspenseBoundary, createSuspenseBoundary,
normalizeSuspenseChildren normalizeSuspenseChildren
} from './suspense' } from './suspense'
import { provide } from './apiInject'
const prodEffectOptions = { const prodEffectOptions = {
scheduler: queueJob scheduler: queueJob
@ -88,9 +86,11 @@ export interface RendererOptions<HostNode = any, HostElement = any> {
isSVG: boolean, isSVG: boolean,
prevChildren?: VNode<HostNode, HostElement>[], prevChildren?: VNode<HostNode, HostElement>[],
parentComponent?: ComponentInternalInstance | null, parentComponent?: ComponentInternalInstance | null,
parentSuspense?: SuspenseBoundary<HostNode, HostElement> | null,
unmountChildren?: ( unmountChildren?: (
children: VNode<HostNode, HostElement>[], children: VNode<HostNode, HostElement>[],
parentComponent: ComponentInternalInstance | null parentComponent: ComponentInternalInstance | null,
parentSuspense: SuspenseBoundary<HostNode, HostElement> | null
) => void ) => void
): void ): void
insert(el: HostNode, parent: HostElement, anchor?: HostNode | null): void insert(el: HostNode, parent: HostElement, anchor?: HostNode | null): void
@ -136,6 +136,7 @@ export function createRenderer<
} { } {
type HostVNode = VNode<HostNode, HostElement> type HostVNode = VNode<HostNode, HostElement>
type HostVNodeChildren = VNodeChildren<HostNode, HostElement> type HostVNodeChildren = VNodeChildren<HostNode, HostElement>
type HostSuspsenseBoundary = SuspenseBoundary<HostNode, HostElement>
const { const {
insert: hostInsert, insert: hostInsert,
@ -157,13 +158,14 @@ export function createRenderer<
container: HostElement, container: HostElement,
anchor: HostNode | null = null, anchor: HostNode | null = null,
parentComponent: ComponentInternalInstance | null = null, parentComponent: ComponentInternalInstance | null = null,
parentSuspense: HostSuspsenseBoundary | null = null,
isSVG: boolean = false, isSVG: boolean = false,
optimized: boolean = false optimized: boolean = false
) { ) {
// patching & not same type, unmount old tree // patching & not same type, unmount old tree
if (n1 != null && !isSameType(n1, n2)) { if (n1 != null && !isSameType(n1, n2)) {
anchor = getNextHostNode(n1) anchor = getNextHostNode(n1)
unmount(n1, parentComponent, true) unmount(n1, parentComponent, parentSuspense, true)
n1 = null n1 = null
} }
@ -182,6 +184,7 @@ export function createRenderer<
container, container,
anchor, anchor,
parentComponent, parentComponent,
parentSuspense,
isSVG, isSVG,
optimized optimized
) )
@ -193,6 +196,7 @@ export function createRenderer<
container, container,
anchor, anchor,
parentComponent, parentComponent,
parentSuspense,
isSVG, isSVG,
optimized optimized
) )
@ -205,6 +209,7 @@ export function createRenderer<
container, container,
anchor, anchor,
parentComponent, parentComponent,
parentSuspense,
isSVG, isSVG,
optimized optimized
) )
@ -220,6 +225,7 @@ export function createRenderer<
container, container,
anchor, anchor,
parentComponent, parentComponent,
parentSuspense,
isSVG, isSVG,
optimized optimized
) )
@ -230,6 +236,7 @@ export function createRenderer<
container, container,
anchor, anchor,
parentComponent, parentComponent,
parentSuspense,
isSVG, isSVG,
optimized optimized
) )
@ -278,13 +285,21 @@ export function createRenderer<
container: HostElement, container: HostElement,
anchor: HostNode | null, anchor: HostNode | null,
parentComponent: ComponentInternalInstance | null, parentComponent: ComponentInternalInstance | null,
parentSuspense: HostSuspsenseBoundary | null,
isSVG: boolean, isSVG: boolean,
optimized: boolean optimized: boolean
) { ) {
if (n1 == null) { if (n1 == null) {
mountElement(n2, container, anchor, parentComponent, isSVG) mountElement(
n2,
container,
anchor,
parentComponent,
parentSuspense,
isSVG
)
} else { } else {
patchElement(n1, n2, parentComponent, isSVG, optimized) patchElement(n1, n2, parentComponent, parentSuspense, isSVG, optimized)
} }
if (n2.ref !== null && parentComponent !== null) { if (n2.ref !== null && parentComponent !== null) {
setRef(n2.ref, n1 && n1.ref, parentComponent, n2.el) setRef(n2.ref, n1 && n1.ref, parentComponent, n2.el)
@ -296,6 +311,7 @@ export function createRenderer<
container: HostElement, container: HostElement,
anchor: HostNode | null, anchor: HostNode | null,
parentComponent: ComponentInternalInstance | null, parentComponent: ComponentInternalInstance | null,
parentSuspense: HostSuspsenseBoundary | null,
isSVG: boolean isSVG: boolean
) { ) {
const tag = vnode.type as string const tag = vnode.type as string
@ -319,6 +335,7 @@ export function createRenderer<
el, el,
null, null,
parentComponent, parentComponent,
parentSuspense,
isSVG isSVG
) )
} }
@ -335,12 +352,21 @@ export function createRenderer<
container: HostElement, container: HostElement,
anchor: HostNode | null, anchor: HostNode | null,
parentComponent: ComponentInternalInstance | null, parentComponent: ComponentInternalInstance | null,
parentSuspense: HostSuspsenseBoundary | null,
isSVG: boolean, isSVG: boolean,
start: number = 0 start: number = 0
) { ) {
for (let i = start; i < children.length; i++) { for (let i = start; i < children.length; i++) {
const child = (children[i] = normalizeVNode(children[i])) const child = (children[i] = normalizeVNode(children[i]))
patch(null, child, container, anchor, parentComponent, isSVG) patch(
null,
child,
container,
anchor,
parentComponent,
parentSuspense,
isSVG
)
} }
} }
@ -348,6 +374,7 @@ export function createRenderer<
n1: HostVNode, n1: HostVNode,
n2: HostVNode, n2: HostVNode,
parentComponent: ComponentInternalInstance | null, parentComponent: ComponentInternalInstance | null,
parentSuspense: HostSuspsenseBoundary | null,
isSVG: boolean, isSVG: boolean,
optimized: boolean optimized: boolean
) { ) {
@ -368,7 +395,15 @@ export function createRenderer<
if (patchFlag & PatchFlags.FULL_PROPS) { if (patchFlag & PatchFlags.FULL_PROPS) {
// element props contain dynamic keys, full diff needed // element props contain dynamic keys, full diff needed
patchProps(el, n2, oldProps, newProps, parentComponent, isSVG) patchProps(
el,
n2,
oldProps,
newProps,
parentComponent,
parentSuspense,
isSVG
)
} else { } else {
// class // class
// this flag is matched when the element has dynamic class bindings. // this flag is matched when the element has dynamic class bindings.
@ -406,6 +441,7 @@ export function createRenderer<
isSVG, isSVG,
n1.children as HostVNode[], n1.children as HostVNode[],
parentComponent, parentComponent,
parentSuspense,
unmountChildren unmountChildren
) )
} }
@ -424,7 +460,15 @@ export function createRenderer<
} }
} else if (!optimized) { } else if (!optimized) {
// unoptimized, full diff // unoptimized, full diff
patchProps(el, n2, oldProps, newProps, parentComponent, isSVG) patchProps(
el,
n2,
oldProps,
newProps,
parentComponent,
parentSuspense,
isSVG
)
} }
if (dynamicChildren != null) { if (dynamicChildren != null) {
@ -437,13 +481,14 @@ export function createRenderer<
el, el,
null, null,
parentComponent, parentComponent,
parentSuspense,
isSVG, isSVG,
true true
) )
} }
} else if (!optimized) { } else if (!optimized) {
// full diff // full diff
patchChildren(n1, n2, el, null, parentComponent, isSVG) patchChildren(n1, n2, el, null, parentComponent, parentSuspense, isSVG)
} }
if (newProps.vnodeUpdated != null) { if (newProps.vnodeUpdated != null) {
@ -459,6 +504,7 @@ export function createRenderer<
oldProps: any, oldProps: any,
newProps: any, newProps: any,
parentComponent: ComponentInternalInstance | null, parentComponent: ComponentInternalInstance | null,
parentSuspense: HostSuspsenseBoundary | null,
isSVG: boolean isSVG: boolean
) { ) {
if (oldProps !== newProps) { if (oldProps !== newProps) {
@ -475,6 +521,7 @@ export function createRenderer<
isSVG, isSVG,
vnode.children as HostVNode[], vnode.children as HostVNode[],
parentComponent, parentComponent,
parentSuspense,
unmountChildren unmountChildren
) )
} }
@ -491,6 +538,7 @@ export function createRenderer<
isSVG, isSVG,
vnode.children as HostVNode[], vnode.children as HostVNode[],
parentComponent, parentComponent,
parentSuspense,
unmountChildren unmountChildren
) )
} }
@ -505,6 +553,7 @@ export function createRenderer<
container: HostElement, container: HostElement,
anchor: HostNode | null, anchor: HostNode | null,
parentComponent: ComponentInternalInstance | null, parentComponent: ComponentInternalInstance | null,
parentSuspense: HostSuspsenseBoundary | null,
isSVG: boolean, isSVG: boolean,
optimized: boolean optimized: boolean
) { ) {
@ -525,6 +574,7 @@ export function createRenderer<
container, container,
fragmentEndAnchor, fragmentEndAnchor,
parentComponent, parentComponent,
parentSuspense,
isSVG isSVG
) )
} else { } else {
@ -534,6 +584,7 @@ export function createRenderer<
container, container,
fragmentEndAnchor, fragmentEndAnchor,
parentComponent, parentComponent,
parentSuspense,
isSVG, isSVG,
optimized optimized
) )
@ -546,6 +597,7 @@ export function createRenderer<
container: HostElement, container: HostElement,
anchor: HostNode | null, anchor: HostNode | null,
parentComponent: ComponentInternalInstance | null, parentComponent: ComponentInternalInstance | null,
parentSuspense: HostSuspsenseBoundary | null,
isSVG: boolean, isSVG: boolean,
optimized: boolean optimized: boolean
) { ) {
@ -564,6 +616,7 @@ export function createRenderer<
target, target,
null, null,
parentComponent, parentComponent,
parentSuspense,
isSVG isSVG
) )
} }
@ -576,7 +629,15 @@ export function createRenderer<
if (patchFlag === PatchFlags.TEXT) { if (patchFlag === PatchFlags.TEXT) {
hostSetElementText(target, children as string) hostSetElementText(target, children as string)
} else if (!optimized) { } else if (!optimized) {
patchChildren(n1, n2, target, null, parentComponent, isSVG) patchChildren(
n1,
n2,
target,
null,
parentComponent,
parentSuspense,
isSVG
)
} }
// target changed // target changed
if (targetSelector !== (n1.props && n1.props.target)) { if (targetSelector !== (n1.props && n1.props.target)) {
@ -608,9 +669,9 @@ export function createRenderer<
container: HostElement, container: HostElement,
anchor: HostNode | null, anchor: HostNode | null,
parentComponent: ComponentInternalInstance | null, parentComponent: ComponentInternalInstance | null,
parentSuspense: HostSuspsenseBoundary | null,
isSVG: boolean, isSVG: boolean,
optimized: boolean, optimized: boolean
parentSuspense: SuspenseBoundary<HostNode, HostElement> | null = null
) { ) {
if (n1 == null) { if (n1 == null) {
const suspense = (n2.suspense = createSuspenseBoundary( const suspense = (n2.suspense = createSuspenseBoundary(
@ -623,7 +684,7 @@ export function createRenderer<
function resolveSuspense() { function resolveSuspense() {
const { subTree, fallbackTree, bufferedJobs, vnode } = suspense const { subTree, fallbackTree, bufferedJobs, vnode } = suspense
// unmount fallback tree // unmount fallback tree
unmount(fallbackTree as HostVNode, parentComponent, true) unmount(fallbackTree as HostVNode, parentComponent, suspense, true)
// move content from off-dom container to actual container // move content from off-dom container to actual container
move(subTree as HostVNode, container, anchor) move(subTree as HostVNode, container, anchor)
const el = (vnode.el = (subTree as HostVNode).el as HostNode) const el = (vnode.el = (subTree as HostVNode).el as HostNode)
@ -656,13 +717,6 @@ export function createRenderer<
} }
} }
// TODO pass it down as an arg instead
if (parentComponent) {
setCurrentInstance(parentComponent)
provide('suspense', suspense)
setCurrentInstance(null)
}
const { content, fallback } = normalizeSuspenseChildren(n2) const { content, fallback } = normalizeSuspenseChildren(n2)
suspense.subTree = content suspense.subTree = content
suspense.fallbackTree = fallback suspense.fallbackTree = fallback
@ -675,6 +729,7 @@ export function createRenderer<
suspense.container, suspense.container,
null, null,
parentComponent, parentComponent,
suspense,
isSVG, isSVG,
optimized optimized
) )
@ -687,6 +742,7 @@ export function createRenderer<
container, container,
anchor, anchor,
parentComponent, parentComponent,
suspense,
isSVG, isSVG,
optimized optimized
) )
@ -696,10 +752,7 @@ export function createRenderer<
suspense.resolve() suspense.resolve()
} }
} else { } else {
const suspense = (n2.suspense = n1.suspense) as SuspenseBoundary< const suspense = (n2.suspense = n1.suspense) as HostSuspsenseBoundary
HostNode,
HostElement
>
suspense.vnode = n2 suspense.vnode = n2
const { content, fallback } = normalizeSuspenseChildren(n2) const { content, fallback } = normalizeSuspenseChildren(n2)
const oldSubTree = (suspense.oldSubTree = suspense.subTree) const oldSubTree = (suspense.oldSubTree = suspense.subTree)
@ -713,6 +766,7 @@ export function createRenderer<
suspense.container, suspense.container,
null, null,
parentComponent, parentComponent,
suspense,
isSVG, isSVG,
optimized optimized
) )
@ -724,6 +778,7 @@ export function createRenderer<
container, container,
anchor, anchor,
parentComponent, parentComponent,
suspense,
isSVG, isSVG,
optimized optimized
) )
@ -739,6 +794,7 @@ export function createRenderer<
container, container,
anchor, anchor,
parentComponent, parentComponent,
suspense,
isSVG, isSVG,
optimized optimized
) )
@ -753,11 +809,19 @@ export function createRenderer<
container: HostElement, container: HostElement,
anchor: HostNode | null, anchor: HostNode | null,
parentComponent: ComponentInternalInstance | null, parentComponent: ComponentInternalInstance | null,
parentSuspense: HostSuspsenseBoundary | null,
isSVG: boolean, isSVG: boolean,
optimized: boolean optimized: boolean
) { ) {
if (n1 == null) { if (n1 == null) {
mountComponent(n2, container, anchor, parentComponent, isSVG) mountComponent(
n2,
container,
anchor,
parentComponent,
parentSuspense,
isSVG
)
} else { } else {
const instance = (n2.component = const instance = (n2.component =
n1.component) as ComponentInternalInstance n1.component) as ComponentInternalInstance
@ -796,6 +860,7 @@ export function createRenderer<
container: HostElement, container: HostElement,
anchor: HostNode | null, anchor: HostNode | null,
parentComponent: ComponentInternalInstance | null, parentComponent: ComponentInternalInstance | null,
parentSuspense: HostSuspsenseBoundary | null,
isSVG: boolean isSVG: boolean
) { ) {
const instance: ComponentInternalInstance = (initialVNode.component = createComponentInstance( const instance: ComponentInternalInstance = (initialVNode.component = createComponentInstance(
@ -820,21 +885,26 @@ export function createRenderer<
// setup() is async. This component relies on async logic to be resolved // setup() is async. This component relies on async logic to be resolved
// before proceeding // before proceeding
if (__FEATURE_SUSPENSE__ && instance.asyncDep) { if (__FEATURE_SUSPENSE__ && instance.asyncDep) {
// TODO use context suspense if (!parentSuspense) {
const suspense = (instance as any).provides.suspense
if (!suspense) {
throw new Error('Async component without a suspense boundary!') throw new Error('Async component without a suspense boundary!')
} }
suspense.deps++ parentSuspense.deps++
instance.asyncDep.then(asyncSetupResult => { instance.asyncDep.then(asyncSetupResult => {
suspense.deps-- parentSuspense.deps--
// retry from this component // retry from this component
instance.asyncResolved = true instance.asyncResolved = true
handleSetupResult(instance, asyncSetupResult) handleSetupResult(instance, asyncSetupResult)
setupRenderEffect(instance, initialVNode, container, anchor, isSVG) setupRenderEffect(
instance,
parentSuspense,
initialVNode,
container,
anchor,
isSVG
)
updateHOCHostEl(instance, initialVNode.el as HostNode) updateHOCHostEl(instance, initialVNode.el as HostNode)
if (suspense.deps === 0) { if (parentSuspense.deps === 0) {
suspense.resolve() parentSuspense.resolve()
} }
}) })
// give it a placeholder // give it a placeholder
@ -844,7 +914,14 @@ export function createRenderer<
return return
} }
setupRenderEffect(instance, initialVNode, container, anchor, isSVG) setupRenderEffect(
instance,
parentSuspense,
initialVNode,
container,
anchor,
isSVG
)
if (__DEV__) { if (__DEV__) {
popWarningContext() popWarningContext()
@ -853,6 +930,7 @@ export function createRenderer<
function setupRenderEffect( function setupRenderEffect(
instance: ComponentInternalInstance, instance: ComponentInternalInstance,
parentSuspense: HostSuspsenseBoundary | null,
initialVNode: HostVNode, initialVNode: HostVNode,
container: HostElement, container: HostElement,
anchor: HostNode | null, anchor: HostNode | null,
@ -867,7 +945,7 @@ export function createRenderer<
if (instance.bm !== null) { if (instance.bm !== null) {
invokeHooks(instance.bm) invokeHooks(instance.bm)
} }
patch(null, subTree, container, anchor, instance, isSVG) patch(null, subTree, container, anchor, instance, parentSuspense, isSVG)
initialVNode.el = subTree.el initialVNode.el = subTree.el
// mounted hook // mounted hook
if (instance.m !== null) { if (instance.m !== null) {
@ -911,6 +989,7 @@ export function createRenderer<
// anchor may have changed if it's in a fragment // anchor may have changed if it's in a fragment
getNextHostNode(prevTree), getNextHostNode(prevTree),
instance, instance,
parentSuspense,
isSVG isSVG
) )
let current = instance.vnode let current = instance.vnode
@ -949,6 +1028,7 @@ export function createRenderer<
container: HostElement, container: HostElement,
anchor: HostNode | null, anchor: HostNode | null,
parentComponent: ComponentInternalInstance | null, parentComponent: ComponentInternalInstance | null,
parentSuspense: HostSuspsenseBoundary | null,
isSVG: boolean, isSVG: boolean,
optimized: boolean = false optimized: boolean = false
) { ) {
@ -968,6 +1048,7 @@ export function createRenderer<
container, container,
anchor, anchor,
parentComponent, parentComponent,
parentSuspense,
isSVG, isSVG,
optimized optimized
) )
@ -980,6 +1061,7 @@ export function createRenderer<
container, container,
anchor, anchor,
parentComponent, parentComponent,
parentSuspense,
isSVG, isSVG,
optimized optimized
) )
@ -991,7 +1073,7 @@ export function createRenderer<
if (shapeFlag & ShapeFlags.TEXT_CHILDREN) { if (shapeFlag & ShapeFlags.TEXT_CHILDREN) {
// text children fast path // text children fast path
if (prevShapeFlag & ShapeFlags.ARRAY_CHILDREN) { if (prevShapeFlag & ShapeFlags.ARRAY_CHILDREN) {
unmountChildren(c1 as HostVNode[], parentComponent) unmountChildren(c1 as HostVNode[], parentComponent, parentSuspense)
} }
if (c2 !== c1) { if (c2 !== c1) {
hostSetElementText(container, c2 as string) hostSetElementText(container, c2 as string)
@ -1007,12 +1089,18 @@ export function createRenderer<
container, container,
anchor, anchor,
parentComponent, parentComponent,
parentSuspense,
isSVG, isSVG,
optimized optimized
) )
} else { } else {
// no new children, just unmount old // no new children, just unmount old
unmountChildren(c1 as HostVNode[], parentComponent, true) unmountChildren(
c1 as HostVNode[],
parentComponent,
parentSuspense,
true
)
} }
} else { } else {
// prev children was text OR null // prev children was text OR null
@ -1027,6 +1115,7 @@ export function createRenderer<
container, container,
anchor, anchor,
parentComponent, parentComponent,
parentSuspense,
isSVG isSVG
) )
} }
@ -1040,6 +1129,7 @@ export function createRenderer<
container: HostElement, container: HostElement,
anchor: HostNode | null, anchor: HostNode | null,
parentComponent: ComponentInternalInstance | null, parentComponent: ComponentInternalInstance | null,
parentSuspense: HostSuspsenseBoundary | null,
isSVG: boolean, isSVG: boolean,
optimized: boolean optimized: boolean
) { ) {
@ -1057,16 +1147,25 @@ export function createRenderer<
container, container,
null, null,
parentComponent, parentComponent,
parentSuspense,
isSVG, isSVG,
optimized optimized
) )
} }
if (oldLength > newLength) { if (oldLength > newLength) {
// remove old // remove old
unmountChildren(c1, parentComponent, true, commonLength) unmountChildren(c1, parentComponent, parentSuspense, true, commonLength)
} else { } else {
// mount new // mount new
mountChildren(c2, container, anchor, parentComponent, isSVG, commonLength) mountChildren(
c2,
container,
anchor,
parentComponent,
parentSuspense,
isSVG,
commonLength
)
} }
} }
@ -1077,6 +1176,7 @@ export function createRenderer<
container: HostElement, container: HostElement,
parentAnchor: HostNode | null, parentAnchor: HostNode | null,
parentComponent: ComponentInternalInstance | null, parentComponent: ComponentInternalInstance | null,
parentSuspense: HostSuspsenseBoundary | null,
isSVG: boolean, isSVG: boolean,
optimized: boolean optimized: boolean
) { ) {
@ -1098,6 +1198,7 @@ export function createRenderer<
container, container,
parentAnchor, parentAnchor,
parentComponent, parentComponent,
parentSuspense,
isSVG, isSVG,
optimized optimized
) )
@ -1120,6 +1221,7 @@ export function createRenderer<
container, container,
parentAnchor, parentAnchor,
parentComponent, parentComponent,
parentSuspense,
isSVG, isSVG,
optimized optimized
) )
@ -1149,6 +1251,7 @@ export function createRenderer<
container, container,
anchor, anchor,
parentComponent, parentComponent,
parentSuspense,
isSVG isSVG
) )
i++ i++
@ -1165,7 +1268,7 @@ export function createRenderer<
// i = 0, e1 = 0, e2 = -1 // i = 0, e1 = 0, e2 = -1
else if (i > e2) { else if (i > e2) {
while (i <= e1) { while (i <= e1) {
unmount(c1[i], parentComponent, true) unmount(c1[i], parentComponent, parentSuspense, true)
i++ i++
} }
} }
@ -1214,7 +1317,7 @@ export function createRenderer<
const prevChild = c1[i] const prevChild = c1[i]
if (patched >= toBePatched) { if (patched >= toBePatched) {
// all new children have been patched so this can only be a removal // all new children have been patched so this can only be a removal
unmount(prevChild, parentComponent, true) unmount(prevChild, parentComponent, parentSuspense, true)
continue continue
} }
let newIndex let newIndex
@ -1230,7 +1333,7 @@ export function createRenderer<
} }
} }
if (newIndex === undefined) { if (newIndex === undefined) {
unmount(prevChild, parentComponent, true) unmount(prevChild, parentComponent, parentSuspense, true)
} else { } else {
newIndexToOldIndexMap[newIndex - s2] = i + 1 newIndexToOldIndexMap[newIndex - s2] = i + 1
if (newIndex >= maxNewIndexSoFar) { if (newIndex >= maxNewIndexSoFar) {
@ -1244,6 +1347,7 @@ export function createRenderer<
container, container,
null, null,
parentComponent, parentComponent,
parentSuspense,
isSVG, isSVG,
optimized optimized
) )
@ -1267,7 +1371,15 @@ export function createRenderer<
: parentAnchor : parentAnchor
if (newIndexToOldIndexMap[i] === 0) { if (newIndexToOldIndexMap[i] === 0) {
// mount new // mount new
patch(null, nextChild, container, anchor, parentComponent, isSVG) patch(
null,
nextChild,
container,
anchor,
parentComponent,
parentSuspense,
isSVG
)
} else if (moved) { } else if (moved) {
// move if: // move if:
// There is no stable subsequence (e.g. a reverse) // There is no stable subsequence (e.g. a reverse)
@ -1310,6 +1422,7 @@ export function createRenderer<
function unmount( function unmount(
vnode: HostVNode, vnode: HostVNode,
parentComponent: ComponentInternalInstance | null, parentComponent: ComponentInternalInstance | null,
parentSuspense: HostSuspsenseBoundary | null,
doRemove?: boolean doRemove?: boolean
) { ) {
const { const {
@ -1330,12 +1443,17 @@ export function createRenderer<
} }
if (component != null) { if (component != null) {
unmountComponent(component, doRemove) unmountComponent(component, parentSuspense, doRemove)
return return
} }
if (__FEATURE_SUSPENSE__ && suspense != null) { if (__FEATURE_SUSPENSE__ && suspense != null) {
unmount(suspense.subTree as HostVNode, parentComponent, doRemove) unmount(
suspense.subTree as HostVNode,
parentComponent,
parentSuspense,
doRemove
)
return return
} }
@ -1345,11 +1463,17 @@ export function createRenderer<
const shouldRemoveChildren = type === Fragment && doRemove const shouldRemoveChildren = type === Fragment && doRemove
if (dynamicChildren != null) { if (dynamicChildren != null) {
unmountChildren(dynamicChildren, parentComponent, shouldRemoveChildren) unmountChildren(
dynamicChildren,
parentComponent,
parentSuspense,
shouldRemoveChildren
)
} else if (shapeFlag & ShapeFlags.ARRAY_CHILDREN) { } else if (shapeFlag & ShapeFlags.ARRAY_CHILDREN) {
unmountChildren( unmountChildren(
children as HostVNode[], children as HostVNode[],
parentComponent, parentComponent,
parentSuspense,
shouldRemoveChildren shouldRemoveChildren
) )
} }
@ -1368,6 +1492,7 @@ export function createRenderer<
function unmountComponent( function unmountComponent(
instance: ComponentInternalInstance, instance: ComponentInternalInstance,
parentSuspense: HostSuspsenseBoundary | null,
doRemove?: boolean doRemove?: boolean
) { ) {
const { bum, effects, update, subTree, um } = instance const { bum, effects, update, subTree, um } = instance
@ -1381,7 +1506,7 @@ export function createRenderer<
} }
} }
stop(update) stop(update)
unmount(subTree, instance, doRemove) unmount(subTree, instance, parentSuspense, doRemove)
// unmounted hook // unmounted hook
if (um !== null) { if (um !== null) {
queuePostFlushCb(um) queuePostFlushCb(um)
@ -1391,11 +1516,12 @@ export function createRenderer<
function unmountChildren( function unmountChildren(
children: HostVNode[], children: HostVNode[],
parentComponent: ComponentInternalInstance | null, parentComponent: ComponentInternalInstance | null,
parentSuspense: HostSuspsenseBoundary | null,
doRemove?: boolean, doRemove?: boolean,
start: number = 0 start: number = 0
) { ) {
for (let i = start; i < children.length; i++) { for (let i = start; i < children.length; i++) {
unmount(children[i], parentComponent, doRemove) unmount(children[i], parentComponent, parentSuspense, doRemove)
} }
} }
@ -1457,7 +1583,7 @@ export function createRenderer<
} }
if (vnode == null) { if (vnode == null) {
if (container._vnode) { if (container._vnode) {
unmount(container._vnode, null, true) unmount(container._vnode, null, null, true)
} }
} else { } else {
patch(container._vnode || null, vnode, container) patch(container._vnode || null, vnode, container)

View File

@ -7,10 +7,11 @@ export function patchDOMProp(
// unmounted. // unmounted.
prevChildren: any, prevChildren: any,
parentComponent: any, parentComponent: any,
parentSuspense: any,
unmountChildren: any unmountChildren: any
) { ) {
if ((key === 'innerHTML' || key === 'textContent') && prevChildren != null) { if ((key === 'innerHTML' || key === 'textContent') && prevChildren != null) {
unmountChildren(prevChildren, parentComponent) unmountChildren(prevChildren, parentComponent, parentSuspense)
} }
el[key] = value == null ? '' : value el[key] = value == null ? '' : value
} }