diff --git a/src/primitives/KeepAlive.tsx b/src/primitives/KeepAlive.tsx index 7cda551..9262138 100644 --- a/src/primitives/KeepAlive.tsx +++ b/src/primitives/KeepAlive.tsx @@ -5,12 +5,15 @@ import { chainFunctions } from './utils/chainFunctions.js'; export interface KeepAliveElement { id: string; - owner: s.Owner | null; - children: s.JSX.Element; + // owner / children / dispose are populated lazily — the preload path + // creates a partial entry holding only `id` + `isAlive` until the route + // mounts, so callers must null-check before use. + owner?: s.Owner | null; + children?: s.JSX.Element; routeSignal?: s.Signal; isAlive?: s.Accessor; setIsAlive?: (v: boolean) => void; - dispose: () => void; + dispose?: () => void; } const keepAliveElements = new Map(); @@ -40,7 +43,7 @@ const _removeKeepAlive = ( ): void => { const element = map.get(id); if (element) { - (element.children as unknown as ElementNode)?.destroy(); + (element.children as unknown as ElementNode | undefined)?.destroy(); element.dispose?.(); map.delete(id); } @@ -53,7 +56,7 @@ export const removeKeepAliveRoute = (id: string): void => const _clearKeepAlive = (map: Map): void => { map.forEach((element) => { - (element.children as unknown as ElementNode)?.destroy(); + (element.children as unknown as ElementNode | undefined)?.destroy(); element.dispose?.(); }); map.clear(); @@ -109,13 +112,13 @@ const createKeepAliveComponent = ( ) => { return (props: s.ParentProps) => { let existing = map.get(props.id); + const existingChild = existing?.children as ElementNode | undefined; if ( existing && - (props.shouldDispose?.(props.id) || - (existing.children as unknown as ElementNode)?.destroyed) + (props.shouldDispose?.(props.id) || existingChild?.destroyed) ) { - (existing.children as unknown as ElementNode).destroy(); + existingChild?.destroy(); existing.dispose?.(); map.delete(props.id); existing = undefined; @@ -138,8 +141,8 @@ const createKeepAliveComponent = ( }); return children; }); - } else if (existing && !existing.children) { - existing.children = s.runWithOwner(existing.owner, () => + } else if (!existing.children) { + existing.children = s.runWithOwner(existing.owner ?? null, () => wrapChildren(props, existing.setIsAlive), ); } @@ -175,18 +178,14 @@ export const KeepAliveRoute = ( const key = props.id || props.path; let savedFocusedElement: ElementNode | undefined; - const getExisting = () => { + const getExisting = (): KeepAliveElement => { let existing = keepAliveRouteElements.get(key); if (!existing) { const [isAlive, setIsAlive] = s.createSignal(true); - existing = { - id: key, - isAlive, - setIsAlive, - } as any; - keepAliveRouteElements.set(key, existing!); + existing = { id: key, isAlive, setIsAlive }; + keepAliveRouteElements.set(key, existing); } - return existing!; + return existing; }; const onRemove = chainFunctions(props.onRemove, (elm: ElementNode) => { @@ -216,13 +215,13 @@ export const KeepAliveRoute = ( const preload = props.preload ? (preloadProps: RoutePreloadFuncArgs) => { let existing = getExisting(); + const existingChild = existing.children as unknown as ElementNode | undefined; if ( - existing.children && - (props.shouldDispose?.(key) || - (existing.children as unknown as ElementNode)?.destroyed) + existingChild && + (props.shouldDispose?.(key) || existingChild.destroyed) ) { - (existing.children as unknown as ElementNode).destroy(); + existingChild.destroy(); existing.dispose?.(); keepAliveRouteElements.delete(key); existing = getExisting(); @@ -235,7 +234,7 @@ export const KeepAliveRoute = ( return props.preload!({ ...preloadProps, isAlive: existing.isAlive! }); }); } else if (existing.children) { - (existing.children as unknown as ElementNode)?.setFocus(); + (existing.children as unknown as ElementNode).setFocus(); return props.preload!({ ...preloadProps, isAlive: existing.isAlive! }); } else { return props.preload!({