wip: handle suspense as component root el update

This commit is contained in:
Evan You 2019-09-10 11:43:17 -04:00
parent 3959a2a2e1
commit 0fff3a6ef5

View File

@ -613,12 +613,25 @@ export function createRenderer<
parentSuspense: SuspenseBoundary<HostNode, HostElement> | null = null parentSuspense: SuspenseBoundary<HostNode, HostElement> | null = null
) { ) {
if (n1 == null) { if (n1 == null) {
function resolve() { const suspense = (n2.suspense = createSuspenseBoundary(
n2,
parentSuspense,
hostCreateElement('div'),
resolveSuspense
))
function resolveSuspense() {
const { subTree, fallbackTree, bufferedJobs, vnode } = suspense
// unmount fallback tree // unmount fallback tree
unmount(suspense.fallbackTree as HostVNode, parentComponent, true) unmount(fallbackTree as HostVNode, parentComponent, true)
// move content from off-dom container to actual container // move content from off-dom container to actual container
move(suspense.subTree as HostVNode, container, anchor) move(subTree as HostVNode, container, anchor)
suspense.vnode.el = (suspense.subTree as HostVNode).el const el = (vnode.el = (subTree as HostVNode).el as HostNode)
// suspense as the root node of a component...
if (parentComponent && parentComponent.subTree === vnode) {
parentComponent.vnode.el = el
updateHOCHostEl(parentComponent, el)
}
// check if there is a pending parent suspense // check if there is a pending parent suspense
let parent = suspense.parent let parent = suspense.parent
let hasUnresolvedAncestor = false let hasUnresolvedAncestor = false
@ -626,24 +639,22 @@ export function createRenderer<
if (!parent.isResolved) { if (!parent.isResolved) {
// found a pending parent suspense, merge buffered post jobs // found a pending parent suspense, merge buffered post jobs
// into that parent // into that parent
parent.bufferedJobs.push(...suspense.bufferedJobs) parent.bufferedJobs.push(...bufferedJobs)
hasUnresolvedAncestor = true hasUnresolvedAncestor = true
break break
} }
} }
// no pending parent suspense, flush all jobs // no pending parent suspense, flush all jobs
if (!hasUnresolvedAncestor) { if (!hasUnresolvedAncestor) {
queuePostFlushCb(suspense.bufferedJobs) queuePostFlushCb(bufferedJobs)
} }
suspense.isResolved = true suspense.isResolved = true
// invoke @resolve event
const onResolve = vnode.props && vnode.props.onResolve
if (isFunction(onResolve)) {
onResolve()
}
} }
const suspense = (n2.suspense = createSuspenseBoundary(
n2,
parentSuspense,
hostCreateElement('div'),
resolve
))
// TODO pass it down as an arg instead // TODO pass it down as an arg instead
if (parentComponent) { if (parentComponent) {
@ -821,6 +832,7 @@ export function createRenderer<
instance.asyncResolved = true instance.asyncResolved = true
handleSetupResult(instance, asyncSetupResult) handleSetupResult(instance, asyncSetupResult)
setupRenderEffect(instance, initialVNode, container, anchor, isSVG) setupRenderEffect(instance, initialVNode, container, anchor, isSVG)
updateHOCHostEl(instance, initialVNode.el as HostNode)
if (suspense.deps === 0) { if (suspense.deps === 0) {
suspense.resolve() suspense.resolve()
} }
@ -907,11 +919,7 @@ export function createRenderer<
// self-triggered update. In case of HOC, update parent component // self-triggered update. In case of HOC, update parent component
// vnode el. HOC is indicated by parent instance's subTree pointing // vnode el. HOC is indicated by parent instance's subTree pointing
// to child component's vnode // to child component's vnode
let parent = instance.parent updateHOCHostEl(instance, nextTree.el)
while (parent && parent.subTree === current) {
;(current = parent.vnode).el = nextTree.el
parent = parent.parent
}
} }
// upated hook // upated hook
if (instance.u !== null) { if (instance.u !== null) {
@ -925,6 +933,16 @@ export function createRenderer<
}, __DEV__ ? createDevEffectOptions(instance) : prodEffectOptions) }, __DEV__ ? createDevEffectOptions(instance) : prodEffectOptions)
} }
function updateHOCHostEl(
{ vnode, parent }: ComponentInternalInstance,
el: HostNode
) {
while (parent && parent.subTree === vnode) {
;(vnode = parent.vnode).el = el
parent = parent.parent
}
}
function patchChildren( function patchChildren(
n1: HostVNode | null, n1: HostVNode | null,
n2: HostVNode, n2: HostVNode,