ComponentInternalInstance,
createComponentInstance,
setupStatefulComponent,
- handleSetupResult,
- setCurrentInstance
+ handleSetupResult
} from './component'
import {
renderComponentRoot,
createSuspenseBoundary,
normalizeSuspenseChildren
} from './suspense'
-import { provide } from './apiInject'
const prodEffectOptions = {
scheduler: queueJob
isSVG: boolean,
prevChildren?: VNode<HostNode, HostElement>[],
parentComponent?: ComponentInternalInstance | null,
+ parentSuspense?: SuspenseBoundary<HostNode, HostElement> | null,
unmountChildren?: (
children: VNode<HostNode, HostElement>[],
- parentComponent: ComponentInternalInstance | null
+ parentComponent: ComponentInternalInstance | null,
+ parentSuspense: SuspenseBoundary<HostNode, HostElement> | null
) => void
): void
insert(el: HostNode, parent: HostElement, anchor?: HostNode | null): void
} {
type HostVNode = VNode<HostNode, HostElement>
type HostVNodeChildren = VNodeChildren<HostNode, HostElement>
+ type HostSuspsenseBoundary = SuspenseBoundary<HostNode, HostElement>
const {
insert: hostInsert,
container: HostElement,
anchor: HostNode | null = null,
parentComponent: ComponentInternalInstance | null = null,
+ parentSuspense: HostSuspsenseBoundary | null = null,
isSVG: boolean = false,
optimized: boolean = false
) {
// patching & not same type, unmount old tree
if (n1 != null && !isSameType(n1, n2)) {
anchor = getNextHostNode(n1)
- unmount(n1, parentComponent, true)
+ unmount(n1, parentComponent, parentSuspense, true)
n1 = null
}
container,
anchor,
parentComponent,
+ parentSuspense,
isSVG,
optimized
)
container,
anchor,
parentComponent,
+ parentSuspense,
isSVG,
optimized
)
container,
anchor,
parentComponent,
+ parentSuspense,
isSVG,
optimized
)
container,
anchor,
parentComponent,
+ parentSuspense,
isSVG,
optimized
)
container,
anchor,
parentComponent,
+ parentSuspense,
isSVG,
optimized
)
container: HostElement,
anchor: HostNode | null,
parentComponent: ComponentInternalInstance | null,
+ parentSuspense: HostSuspsenseBoundary | null,
isSVG: boolean,
optimized: boolean
) {
if (n1 == null) {
- mountElement(n2, container, anchor, parentComponent, isSVG)
+ mountElement(
+ n2,
+ container,
+ anchor,
+ parentComponent,
+ parentSuspense,
+ isSVG
+ )
} else {
- patchElement(n1, n2, parentComponent, isSVG, optimized)
+ patchElement(n1, n2, parentComponent, parentSuspense, isSVG, optimized)
}
if (n2.ref !== null && parentComponent !== null) {
setRef(n2.ref, n1 && n1.ref, parentComponent, n2.el)
container: HostElement,
anchor: HostNode | null,
parentComponent: ComponentInternalInstance | null,
+ parentSuspense: HostSuspsenseBoundary | null,
isSVG: boolean
) {
const tag = vnode.type as string
el,
null,
parentComponent,
+ parentSuspense,
isSVG
)
}
container: HostElement,
anchor: HostNode | null,
parentComponent: ComponentInternalInstance | null,
+ parentSuspense: HostSuspsenseBoundary | null,
isSVG: boolean,
start: number = 0
) {
for (let i = start; i < children.length; i++) {
const child = (children[i] = normalizeVNode(children[i]))
- patch(null, child, container, anchor, parentComponent, isSVG)
+ patch(
+ null,
+ child,
+ container,
+ anchor,
+ parentComponent,
+ parentSuspense,
+ isSVG
+ )
}
}
n1: HostVNode,
n2: HostVNode,
parentComponent: ComponentInternalInstance | null,
+ parentSuspense: HostSuspsenseBoundary | null,
isSVG: boolean,
optimized: boolean
) {
if (patchFlag & PatchFlags.FULL_PROPS) {
// element props contain dynamic keys, full diff needed
- patchProps(el, n2, oldProps, newProps, parentComponent, isSVG)
+ patchProps(
+ el,
+ n2,
+ oldProps,
+ newProps,
+ parentComponent,
+ parentSuspense,
+ isSVG
+ )
} else {
// class
// this flag is matched when the element has dynamic class bindings.
isSVG,
n1.children as HostVNode[],
parentComponent,
+ parentSuspense,
unmountChildren
)
}
}
} else if (!optimized) {
// unoptimized, full diff
- patchProps(el, n2, oldProps, newProps, parentComponent, isSVG)
+ patchProps(
+ el,
+ n2,
+ oldProps,
+ newProps,
+ parentComponent,
+ parentSuspense,
+ isSVG
+ )
}
if (dynamicChildren != null) {
el,
null,
parentComponent,
+ parentSuspense,
isSVG,
true
)
}
} else if (!optimized) {
// full diff
- patchChildren(n1, n2, el, null, parentComponent, isSVG)
+ patchChildren(n1, n2, el, null, parentComponent, parentSuspense, isSVG)
}
if (newProps.vnodeUpdated != null) {
oldProps: any,
newProps: any,
parentComponent: ComponentInternalInstance | null,
+ parentSuspense: HostSuspsenseBoundary | null,
isSVG: boolean
) {
if (oldProps !== newProps) {
isSVG,
vnode.children as HostVNode[],
parentComponent,
+ parentSuspense,
unmountChildren
)
}
isSVG,
vnode.children as HostVNode[],
parentComponent,
+ parentSuspense,
unmountChildren
)
}
container: HostElement,
anchor: HostNode | null,
parentComponent: ComponentInternalInstance | null,
+ parentSuspense: HostSuspsenseBoundary | null,
isSVG: boolean,
optimized: boolean
) {
container,
fragmentEndAnchor,
parentComponent,
+ parentSuspense,
isSVG
)
} else {
container,
fragmentEndAnchor,
parentComponent,
+ parentSuspense,
isSVG,
optimized
)
container: HostElement,
anchor: HostNode | null,
parentComponent: ComponentInternalInstance | null,
+ parentSuspense: HostSuspsenseBoundary | null,
isSVG: boolean,
optimized: boolean
) {
target,
null,
parentComponent,
+ parentSuspense,
isSVG
)
}
if (patchFlag === PatchFlags.TEXT) {
hostSetElementText(target, children as string)
} else if (!optimized) {
- patchChildren(n1, n2, target, null, parentComponent, isSVG)
+ patchChildren(
+ n1,
+ n2,
+ target,
+ null,
+ parentComponent,
+ parentSuspense,
+ isSVG
+ )
}
// target changed
if (targetSelector !== (n1.props && n1.props.target)) {
container: HostElement,
anchor: HostNode | null,
parentComponent: ComponentInternalInstance | null,
+ parentSuspense: HostSuspsenseBoundary | null,
isSVG: boolean,
- optimized: boolean,
- parentSuspense: SuspenseBoundary<HostNode, HostElement> | null = null
+ optimized: boolean
) {
if (n1 == null) {
const suspense = (n2.suspense = createSuspenseBoundary(
function resolveSuspense() {
const { subTree, fallbackTree, bufferedJobs, vnode } = suspense
// 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(subTree as HostVNode, container, anchor)
const el = (vnode.el = (subTree as HostVNode).el as HostNode)
}
}
- // TODO pass it down as an arg instead
- if (parentComponent) {
- setCurrentInstance(parentComponent)
- provide('suspense', suspense)
- setCurrentInstance(null)
- }
-
const { content, fallback } = normalizeSuspenseChildren(n2)
suspense.subTree = content
suspense.fallbackTree = fallback
suspense.container,
null,
parentComponent,
+ suspense,
isSVG,
optimized
)
container,
anchor,
parentComponent,
+ suspense,
isSVG,
optimized
)
suspense.resolve()
}
} else {
- const suspense = (n2.suspense = n1.suspense) as SuspenseBoundary<
- HostNode,
- HostElement
- >
+ const suspense = (n2.suspense = n1.suspense) as HostSuspsenseBoundary
suspense.vnode = n2
const { content, fallback } = normalizeSuspenseChildren(n2)
const oldSubTree = (suspense.oldSubTree = suspense.subTree)
suspense.container,
null,
parentComponent,
+ suspense,
isSVG,
optimized
)
container,
anchor,
parentComponent,
+ suspense,
isSVG,
optimized
)
container,
anchor,
parentComponent,
+ suspense,
isSVG,
optimized
)
container: HostElement,
anchor: HostNode | null,
parentComponent: ComponentInternalInstance | null,
+ parentSuspense: HostSuspsenseBoundary | null,
isSVG: boolean,
optimized: boolean
) {
if (n1 == null) {
- mountComponent(n2, container, anchor, parentComponent, isSVG)
+ mountComponent(
+ n2,
+ container,
+ anchor,
+ parentComponent,
+ parentSuspense,
+ isSVG
+ )
} else {
const instance = (n2.component =
n1.component) as ComponentInternalInstance
container: HostElement,
anchor: HostNode | null,
parentComponent: ComponentInternalInstance | null,
+ parentSuspense: HostSuspsenseBoundary | null,
isSVG: boolean
) {
const instance: ComponentInternalInstance = (initialVNode.component = createComponentInstance(
// setup() is async. This component relies on async logic to be resolved
// before proceeding
if (__FEATURE_SUSPENSE__ && instance.asyncDep) {
- // TODO use context suspense
- const suspense = (instance as any).provides.suspense
- if (!suspense) {
+ if (!parentSuspense) {
throw new Error('Async component without a suspense boundary!')
}
- suspense.deps++
+ parentSuspense.deps++
instance.asyncDep.then(asyncSetupResult => {
- suspense.deps--
+ parentSuspense.deps--
// retry from this component
instance.asyncResolved = true
handleSetupResult(instance, asyncSetupResult)
- setupRenderEffect(instance, initialVNode, container, anchor, isSVG)
+ setupRenderEffect(
+ instance,
+ parentSuspense,
+ initialVNode,
+ container,
+ anchor,
+ isSVG
+ )
updateHOCHostEl(instance, initialVNode.el as HostNode)
- if (suspense.deps === 0) {
- suspense.resolve()
+ if (parentSuspense.deps === 0) {
+ parentSuspense.resolve()
}
})
// give it a placeholder
return
}
- setupRenderEffect(instance, initialVNode, container, anchor, isSVG)
+ setupRenderEffect(
+ instance,
+ parentSuspense,
+ initialVNode,
+ container,
+ anchor,
+ isSVG
+ )
if (__DEV__) {
popWarningContext()
function setupRenderEffect(
instance: ComponentInternalInstance,
+ parentSuspense: HostSuspsenseBoundary | null,
initialVNode: HostVNode,
container: HostElement,
anchor: HostNode | null,
if (instance.bm !== null) {
invokeHooks(instance.bm)
}
- patch(null, subTree, container, anchor, instance, isSVG)
+ patch(null, subTree, container, anchor, instance, parentSuspense, isSVG)
initialVNode.el = subTree.el
// mounted hook
if (instance.m !== null) {
// anchor may have changed if it's in a fragment
getNextHostNode(prevTree),
instance,
+ parentSuspense,
isSVG
)
let current = instance.vnode
container: HostElement,
anchor: HostNode | null,
parentComponent: ComponentInternalInstance | null,
+ parentSuspense: HostSuspsenseBoundary | null,
isSVG: boolean,
optimized: boolean = false
) {
container,
anchor,
parentComponent,
+ parentSuspense,
isSVG,
optimized
)
container,
anchor,
parentComponent,
+ parentSuspense,
isSVG,
optimized
)
if (shapeFlag & ShapeFlags.TEXT_CHILDREN) {
// text children fast path
if (prevShapeFlag & ShapeFlags.ARRAY_CHILDREN) {
- unmountChildren(c1 as HostVNode[], parentComponent)
+ unmountChildren(c1 as HostVNode[], parentComponent, parentSuspense)
}
if (c2 !== c1) {
hostSetElementText(container, c2 as string)
container,
anchor,
parentComponent,
+ parentSuspense,
isSVG,
optimized
)
} else {
// no new children, just unmount old
- unmountChildren(c1 as HostVNode[], parentComponent, true)
+ unmountChildren(
+ c1 as HostVNode[],
+ parentComponent,
+ parentSuspense,
+ true
+ )
}
} else {
// prev children was text OR null
container,
anchor,
parentComponent,
+ parentSuspense,
isSVG
)
}
container: HostElement,
anchor: HostNode | null,
parentComponent: ComponentInternalInstance | null,
+ parentSuspense: HostSuspsenseBoundary | null,
isSVG: boolean,
optimized: boolean
) {
container,
null,
parentComponent,
+ parentSuspense,
isSVG,
optimized
)
}
if (oldLength > newLength) {
// remove old
- unmountChildren(c1, parentComponent, true, commonLength)
+ unmountChildren(c1, parentComponent, parentSuspense, true, commonLength)
} else {
// mount new
- mountChildren(c2, container, anchor, parentComponent, isSVG, commonLength)
+ mountChildren(
+ c2,
+ container,
+ anchor,
+ parentComponent,
+ parentSuspense,
+ isSVG,
+ commonLength
+ )
}
}
container: HostElement,
parentAnchor: HostNode | null,
parentComponent: ComponentInternalInstance | null,
+ parentSuspense: HostSuspsenseBoundary | null,
isSVG: boolean,
optimized: boolean
) {
container,
parentAnchor,
parentComponent,
+ parentSuspense,
isSVG,
optimized
)
container,
parentAnchor,
parentComponent,
+ parentSuspense,
isSVG,
optimized
)
container,
anchor,
parentComponent,
+ parentSuspense,
isSVG
)
i++
// i = 0, e1 = 0, e2 = -1
else if (i > e2) {
while (i <= e1) {
- unmount(c1[i], parentComponent, true)
+ unmount(c1[i], parentComponent, parentSuspense, true)
i++
}
}
const prevChild = c1[i]
if (patched >= toBePatched) {
// all new children have been patched so this can only be a removal
- unmount(prevChild, parentComponent, true)
+ unmount(prevChild, parentComponent, parentSuspense, true)
continue
}
let newIndex
}
}
if (newIndex === undefined) {
- unmount(prevChild, parentComponent, true)
+ unmount(prevChild, parentComponent, parentSuspense, true)
} else {
newIndexToOldIndexMap[newIndex - s2] = i + 1
if (newIndex >= maxNewIndexSoFar) {
container,
null,
parentComponent,
+ parentSuspense,
isSVG,
optimized
)
: parentAnchor
if (newIndexToOldIndexMap[i] === 0) {
// mount new
- patch(null, nextChild, container, anchor, parentComponent, isSVG)
+ patch(
+ null,
+ nextChild,
+ container,
+ anchor,
+ parentComponent,
+ parentSuspense,
+ isSVG
+ )
} else if (moved) {
// move if:
// There is no stable subsequence (e.g. a reverse)
function unmount(
vnode: HostVNode,
parentComponent: ComponentInternalInstance | null,
+ parentSuspense: HostSuspsenseBoundary | null,
doRemove?: boolean
) {
const {
}
if (component != null) {
- unmountComponent(component, doRemove)
+ unmountComponent(component, parentSuspense, doRemove)
return
}
if (__FEATURE_SUSPENSE__ && suspense != null) {
- unmount(suspense.subTree as HostVNode, parentComponent, doRemove)
+ unmount(
+ suspense.subTree as HostVNode,
+ parentComponent,
+ parentSuspense,
+ doRemove
+ )
return
}
const shouldRemoveChildren = type === Fragment && doRemove
if (dynamicChildren != null) {
- unmountChildren(dynamicChildren, parentComponent, shouldRemoveChildren)
+ unmountChildren(
+ dynamicChildren,
+ parentComponent,
+ parentSuspense,
+ shouldRemoveChildren
+ )
} else if (shapeFlag & ShapeFlags.ARRAY_CHILDREN) {
unmountChildren(
children as HostVNode[],
parentComponent,
+ parentSuspense,
shouldRemoveChildren
)
}
function unmountComponent(
instance: ComponentInternalInstance,
+ parentSuspense: HostSuspsenseBoundary | null,
doRemove?: boolean
) {
const { bum, effects, update, subTree, um } = instance
}
}
stop(update)
- unmount(subTree, instance, doRemove)
+ unmount(subTree, instance, parentSuspense, doRemove)
// unmounted hook
if (um !== null) {
queuePostFlushCb(um)
function unmountChildren(
children: HostVNode[],
parentComponent: ComponentInternalInstance | null,
+ parentSuspense: HostSuspsenseBoundary | null,
doRemove?: boolean,
start: number = 0
) {
for (let i = start; i < children.length; i++) {
- unmount(children[i], parentComponent, doRemove)
+ unmount(children[i], parentComponent, parentSuspense, doRemove)
}
}
}
if (vnode == null) {
if (container._vnode) {
- unmount(container._vnode, null, true)
+ unmount(container._vnode, null, null, true)
}
} else {
patch(container._vnode || null, vnode, container)