shallowRef,
SuspenseProps,
resolveDynamicComponent,
- Fragment
+ Fragment,
+ KeepAlive
} from '@vue/runtime-test'
import { createApp, defineComponent } from 'vue'
import { type RawSlots } from 'packages/runtime-core/src/componentSlots'
expect(serializeInner(root)).toBe(expected)
})
+ // #6416
+ test('KeepAlive with Suspense', async () => {
+ const Async = defineAsyncComponent({
+ render() {
+ return h('div', 'async')
+ }
+ })
+ const Sync = {
+ render() {
+ return h('div', 'sync')
+ }
+ }
+ const components = [Async, Sync]
+ const viewRef = ref(0)
+ const root = nodeOps.createElement('div')
+ const App = {
+ render() {
+ return h(KeepAlive, null, {
+ default: () => {
+ return h(Suspense, null, {
+ default: h(components[viewRef.value]),
+ fallback: h('div', 'Loading-dynamic-components')
+ })
+ }
+ })
+ }
+ }
+ render(h(App), root)
+ expect(serializeInner(root)).toBe(`<div>Loading-dynamic-components</div>`)
+
+ viewRef.value = 1
+ await nextTick()
+ expect(serializeInner(root)).toBe(`<div>sync</div>`)
+
+ viewRef.value = 0
+ await nextTick()
+
+ expect(serializeInner(root)).toBe('<!---->')
+
+ await Promise.all(deps)
+ await nextTick()
+ // when async resolve,it should be <div>async</div>
+ expect(serializeInner(root)).toBe('<div>async</div>')
+
+ viewRef.value = 1
+ await nextTick() //TypeError: Cannot read properties of null (reading 'parentNode'),This has been fixed
+ expect(serializeInner(root)).toBe(`<div>sync</div>`)
+ })
+
describe('warnings', () => {
// base function to check if a combination of slots warns or not
function baseCheckWarn(
export const isSuspense = (type: any): boolean => type.__isSuspense
+// incrementing unique id for every pending branch
+let suspenseId = 0
+
// Suspense exposes a component-like API, and is treated like a component
// in the compiler, but internally it's a special built-in type that hooks
// directly into the renderer.
}
} else {
// toggled before pending tree is resolved
- suspense.pendingId++
+ // increment pending ID. this is used to invalidate async callbacks
+ suspense.pendingId = suspenseId++
if (isHydrating) {
// if toggled before hydration is finished, the current DOM tree is
// no longer valid. set it as the active branch so it will be unmounted
} else {
unmount(pendingBranch, parentComponent, suspense)
}
- // increment pending ID. this is used to invalidate async callbacks
// reset suspense state
suspense.deps = 0
// discard effects from pending branch
triggerEvent(n2, 'onPending')
// mount pending branch in off-dom container
suspense.pendingBranch = newBranch
- suspense.pendingId++
+ if (newBranch.shapeFlag & ShapeFlags.COMPONENT_KEPT_ALIVE) {
+ suspense.pendingId = newBranch.component!.suspenseId!
+ } else {
+ suspense.pendingId = suspenseId++
+ }
patch(
null,
newBranch,