parent
f0eb1978b2
commit
9f24195d2c
@ -23,6 +23,7 @@ import {
|
||||
createApp
|
||||
} from '@vue/runtime-test'
|
||||
import { PatchFlags, SlotFlags } from '@vue/shared'
|
||||
import { SuspenseImpl } from '../src/components/Suspense'
|
||||
|
||||
describe('renderer: optimized mode', () => {
|
||||
let root: TestElement
|
||||
@ -784,4 +785,40 @@ describe('renderer: optimized mode', () => {
|
||||
await nextTick()
|
||||
expect(inner(root)).toBe('<div><div><span>loading</span></div></div>')
|
||||
})
|
||||
|
||||
// #3828
|
||||
test('patch Suspense in optimized mode w/ nested dynamic nodes', async () => {
|
||||
const show = ref(false)
|
||||
|
||||
const app = createApp({
|
||||
render() {
|
||||
return (
|
||||
openBlock(),
|
||||
createBlock(
|
||||
Fragment,
|
||||
null,
|
||||
[
|
||||
(openBlock(),
|
||||
createBlock(SuspenseImpl, null, {
|
||||
default: withCtx(() => [
|
||||
createVNode('div', null, [
|
||||
createVNode('div', null, show.value, PatchFlags.TEXT)
|
||||
])
|
||||
]),
|
||||
_: SlotFlags.STABLE
|
||||
}))
|
||||
],
|
||||
PatchFlags.STABLE_FRAGMENT
|
||||
)
|
||||
)
|
||||
}
|
||||
})
|
||||
|
||||
app.mount(root)
|
||||
expect(inner(root)).toBe('<div><div>false</div></div>')
|
||||
|
||||
show.value = true
|
||||
await nextTick()
|
||||
expect(inner(root)).toBe('<div><div>true</div></div>')
|
||||
})
|
||||
})
|
||||
|
@ -1,9 +1,12 @@
|
||||
import {
|
||||
VNode,
|
||||
normalizeVNode,
|
||||
VNodeChild,
|
||||
VNodeProps,
|
||||
isSameVNodeType
|
||||
isSameVNodeType,
|
||||
openBlock,
|
||||
closeBlock,
|
||||
currentBlock,
|
||||
createVNode
|
||||
} from '../vnode'
|
||||
import { isFunction, isArray, ShapeFlags, toNumber } from '@vue/shared'
|
||||
import { ComponentInternalInstance, handleSetupResult } from '../component'
|
||||
@ -79,7 +82,8 @@ export const SuspenseImpl = {
|
||||
}
|
||||
},
|
||||
hydrate: hydrateSuspense,
|
||||
create: createSuspenseBoundary
|
||||
create: createSuspenseBoundary,
|
||||
normalize: normalizeSuspenseChildren
|
||||
}
|
||||
|
||||
// Force-casted public typing for h and TSX props inference
|
||||
@ -709,31 +713,34 @@ function hydrateSuspense(
|
||||
/* eslint-enable no-restricted-globals */
|
||||
}
|
||||
|
||||
export function normalizeSuspenseChildren(
|
||||
vnode: VNode
|
||||
): {
|
||||
content: VNode
|
||||
fallback: VNode
|
||||
} {
|
||||
function normalizeSuspenseChildren(vnode: VNode) {
|
||||
const { shapeFlag, children } = vnode
|
||||
let content: VNode
|
||||
let fallback: VNode
|
||||
if (shapeFlag & ShapeFlags.SLOTS_CHILDREN) {
|
||||
content = normalizeSuspenseSlot((children as Slots).default)
|
||||
fallback = normalizeSuspenseSlot((children as Slots).fallback)
|
||||
} else {
|
||||
content = normalizeSuspenseSlot(children as VNodeChild)
|
||||
fallback = normalizeVNode(null)
|
||||
}
|
||||
return {
|
||||
content,
|
||||
fallback
|
||||
}
|
||||
const isSlotChildren = shapeFlag & ShapeFlags.SLOTS_CHILDREN
|
||||
vnode.ssContent = normalizeSuspenseSlot(
|
||||
isSlotChildren ? (children as Slots).default : children
|
||||
)
|
||||
vnode.ssFallback = isSlotChildren
|
||||
? normalizeSuspenseSlot((children as Slots).fallback)
|
||||
: createVNode(Comment)
|
||||
}
|
||||
|
||||
function normalizeSuspenseSlot(s: any) {
|
||||
let block: VNode[] | null | undefined
|
||||
if (isFunction(s)) {
|
||||
const isCompiledSlot = s._c
|
||||
if (isCompiledSlot) {
|
||||
// disableTracking: false
|
||||
// allow block tracking for compiled slots
|
||||
// (see ./componentRenderContext.ts)
|
||||
s._d = false
|
||||
openBlock()
|
||||
}
|
||||
s = s()
|
||||
if (isCompiledSlot) {
|
||||
s._d = true
|
||||
block = currentBlock
|
||||
closeBlock()
|
||||
}
|
||||
}
|
||||
if (isArray(s)) {
|
||||
const singleChild = filterSingleRoot(s)
|
||||
@ -742,7 +749,11 @@ function normalizeSuspenseSlot(s: any) {
|
||||
}
|
||||
s = singleChild
|
||||
}
|
||||
return normalizeVNode(s)
|
||||
s = normalizeVNode(s)
|
||||
if (block) {
|
||||
s.dynamicChildren = block.filter(c => c !== s)
|
||||
}
|
||||
return s
|
||||
}
|
||||
|
||||
export function queueEffectWithSuspense(
|
||||
|
@ -26,8 +26,7 @@ import { AppContext } from './apiCreateApp'
|
||||
import {
|
||||
SuspenseImpl,
|
||||
isSuspense,
|
||||
SuspenseBoundary,
|
||||
normalizeSuspenseChildren
|
||||
SuspenseBoundary
|
||||
} from './components/Suspense'
|
||||
import { DirectiveBinding } from './directives'
|
||||
import { TransitionHooks } from './components/BaseTransition'
|
||||
@ -186,7 +185,7 @@ export interface VNode<
|
||||
// structure would be stable. This allows us to skip most children diffing
|
||||
// and only worry about the dynamic nodes (indicated by patch flags).
|
||||
export const blockStack: (VNode[] | null)[] = []
|
||||
let currentBlock: VNode[] | null = null
|
||||
export let currentBlock: VNode[] | null = null
|
||||
|
||||
/**
|
||||
* Open a block.
|
||||
@ -452,9 +451,7 @@ function _createVNode(
|
||||
|
||||
// normalize suspense children
|
||||
if (__FEATURE_SUSPENSE__ && shapeFlag & ShapeFlags.SUSPENSE) {
|
||||
const { content, fallback } = normalizeSuspenseChildren(vnode)
|
||||
vnode.ssContent = content
|
||||
vnode.ssFallback = fallback
|
||||
;(type as typeof SuspenseImpl).normalize(vnode)
|
||||
}
|
||||
|
||||
if (
|
||||
|
Loading…
Reference in New Issue
Block a user