if (!instance || instance.isUnmounted) return
const setupState: any = __DEV__ ? instance.setupState || {} : null
- const refValue = isVaporComponent(el)
- ? getExposed(el) || el
- : el instanceof DynamicFragment
- ? getExposed(el.nodes as VaporComponentInstance) || el.nodes
- : el
+ const refValue = getRefValue(el)
const refs =
instance.refs === EMPTY_OBJ ? (instance.refs = {}) : instance.refs
}
return ref
}
+
+const getRefValue = (el: RefEl) => {
+ if (isVaporComponent(el)) {
+ return getExposed(el) || el
+ } else if (el instanceof DynamicFragment) {
+ return getRefValue(el.nodes as RefEl)
+ }
+ return el
+}
locateHydrationNode()
}
+ // try to get the cached instance if inside keep-alive
if (currentInstance && isKeepAlive(currentInstance)) {
- const cache = (currentInstance as KeepAliveInstance).getCache(component)
- if (cache) return cache
+ const cached = (currentInstance as KeepAliveInstance).getCachedInstance(
+ component,
+ )
+ if (cached) return cached
}
// vdom interop enabled and component is not an explicit vapor component
}
if (instance.bm) invokeArrayFns(instance.bm)
insert(instance.block, parentNode, anchor)
- if (instance.m) queuePostFlushCb(() => invokeArrayFns(instance.m!))
+ if (instance.m) queuePostFlushCb(instance.m!)
if (
instance.shapeFlag! & ShapeFlags.COMPONENT_SHOULD_KEEP_ALIVE &&
instance.a
instance.scope.stop()
if (instance.um) {
- queuePostFlushCb(() => invokeArrayFns(instance.um!))
+ queuePostFlushCb(instance.um!)
}
instance.isUnmounted = true
}
warn,
watch,
} from '@vue/runtime-dom'
-import {
- type Block,
- DynamicFragment,
- insert,
- isFragment,
- isValidBlock,
-} from '../block'
+import { type Block, insert, isFragment } from '../block'
import {
type ObjectVaporComponent,
type VaporComponent,
) => void
deactivate: (instance: VaporComponentInstance) => void
process: (instance: VaporComponentInstance) => void
- getCache: (comp: VaporComponent) => VaporComponentInstance | undefined
+ getCachedInstance: (
+ comp: VaporComponent,
+ ) => VaporComponentInstance | undefined
}
-type CacheKey = PropertyKey | VaporComponent
+type CacheKey = VaporComponent
type Cache = Map<CacheKey, VaporComponentInstance>
type Keys = Set<CacheKey>
export const VaporKeepAliveImpl: ObjectVaporComponent = defineVaporComponent({
name: 'VaporKeepAlive',
- // @ts-expect-error
__isKeepAlive: true,
props: {
include: [String, RegExp, Array],
function cacheBlock() {
const { max } = props
// TODO suspense
- const currentBlock = keepAliveInstance.block!
- if (!isValidBlock(currentBlock)) return
-
- const block = getInnerBlock(currentBlock)!
- if (!block || !shouldCache(block)) return
+ const innerBlock = getInnerBlock(keepAliveInstance.block!)!
+ if (!innerBlock || !shouldCache(innerBlock)) return
- const key = block.type
+ const key = innerBlock.type
if (cache.has(key)) {
// make this key the freshest
keys.delete(key)
pruneCacheEntry(keys.values().next().value!)
}
}
- cache.set(key, (current = block))
+ cache.set(key, (current = innerBlock))
}
onMounted(cacheBlock)
})
})
- keepAliveInstance.getCache = (comp: VaporComponent) => cache.get(comp)
+ keepAliveInstance.getCachedInstance = (comp: VaporComponent) =>
+ cache.get(comp)
- keepAliveInstance.process = (instance: VaporComponentInstance) => {
+ const process = (keepAliveInstance.process = (
+ instance: VaporComponentInstance,
+ ) => {
if (cache.has(instance.type)) {
instance.shapeFlag! |= ShapeFlags.COMPONENT_KEPT_ALIVE
}
if (shouldCache(instance)) {
instance.shapeFlag! |= ShapeFlags.COMPONENT_SHOULD_KEEP_ALIVE
}
- }
+ })
keepAliveInstance.activate = (
instance: VaporComponentInstance,
parentNode: ParentNode,
anchor: Node,
) => {
- const cachedBlock = (current = cache.get(instance.type)!)
- insert((instance.block = cachedBlock.block), parentNode, anchor)
+ current = instance
+ insert(instance.block, parentNode, anchor)
queuePostFlushCb(() => {
instance.isDeactivated = false
if (instance.a) invokeArrayFns(instance.a)
return children
}
- // wrap children in dynamic fragment
- if (!isFragment(children)) {
- const frag = new DynamicFragment()
- frag.update(() => children)
- children = frag
- }
+ // `children` could be either a `VaporComponentInstance` or a `DynamicFragment`
+ // (when using `v-if` or `<component is/>`). For `DynamicFragment` children,
+ // the `shapeFlag` is processed in `DynamicFragment.update`. Here only need
+ // to process the `VaporComponentInstance`
+ if (isVaporComponent(children)) process(children)
function pruneCache(filter: (name: string) => boolean) {
cache.forEach((instance, key) => {
const cached = cache.get(key)
if (cached) {
resetShapeFlag(cached)
+ // don't unmount if the instance is the current one
if (cached !== current) {
unmountComponent(cached)
}