fix(ssr): handle hydrated async component unmounted before resolve

fix #3787
This commit is contained in:
Evan You
2021-05-26 15:26:18 -04:00
parent b57e995edd
commit b46a4dccf6
3 changed files with 77 additions and 3 deletions

View File

@@ -5,7 +5,9 @@ import {
Comment,
Static,
Fragment,
VNodeHook
VNodeHook,
createVNode,
createTextVNode
} from './vnode'
import { flushPostFlushCbs } from './scheduler'
import { ComponentInternalInstance } from './component'
@@ -19,6 +21,7 @@ import {
queueEffectWithSuspense
} from './components/Suspense'
import { TeleportImpl, TeleportVNode } from './components/Teleport'
import { isAsyncWrapper } from './apiAsyncComponent'
export type RootHydrateFunction = (
vnode: VNode<Node, Element>,
@@ -187,12 +190,32 @@ export function createHydrationFunctions(
isSVGContainer(container),
optimized
)
// component may be async, so in the case of fragments we cannot rely
// on component's rendered output to determine the end of the fragment
// instead, we do a lookahead to find the end anchor node.
nextNode = isFragmentStart
? locateClosingAsyncAnchor(node)
: nextSibling(node)
// #3787
// if component is async, it may get moved / unmounted before its
// inner component is loaded, so we need to give it a placeholder
// vnode that matches its adopted DOM.
if (isAsyncWrapper(vnode)) {
let subTree
if (isFragmentStart) {
subTree = createVNode(Fragment)
subTree.anchor = nextNode
? nextNode.previousSibling
: container.lastChild
} else {
subTree =
node.nodeType === 3 ? createTextVNode('') : createVNode('div')
}
subTree.el = node
vnode.component!.subTree = subTree
}
} else if (shapeFlag & ShapeFlags.TELEPORT) {
if (domType !== DOMNodeTypes.COMMENT) {
nextNode = onMismatch()

View File

@@ -1462,7 +1462,7 @@ function baseCreateRenderer(
// which means it won't track dependencies - but it's ok because
// a server-rendered async wrapper is already in resolved state
// and it will never need to change.
hydrateSubTree
() => !instance.isUnmounted && hydrateSubTree()
)
} else {
hydrateSubTree()