diff --git a/.changeset/brave-items-cover.md b/.changeset/brave-items-cover.md new file mode 100644 index 0000000000..ad1de7aa9f --- /dev/null +++ b/.changeset/brave-items-cover.md @@ -0,0 +1,5 @@ +--- +'@ice/runtime': patch +--- + +feat: support props for KeepAliveOutlet diff --git a/examples/with-keep-alive/src/pages/layout.tsx b/examples/with-keep-alive/src/pages/layout.tsx index c50545a199..cef958ddfc 100644 --- a/examples/with-keep-alive/src/pages/layout.tsx +++ b/examples/with-keep-alive/src/pages/layout.tsx @@ -4,7 +4,7 @@ export default function Layout() { return (

Layout

- +
); } diff --git a/packages/runtime/src/KeepAliveOutlet.tsx b/packages/runtime/src/KeepAliveOutlet.tsx index d300e5b977..8c4a667f83 100644 --- a/packages/runtime/src/KeepAliveOutlet.tsx +++ b/packages/runtime/src/KeepAliveOutlet.tsx @@ -10,41 +10,54 @@ interface ActivityItem { pathname: string; } -export default function KeepAliveOutlet() { +interface OutletProps { + // The limitation number of outlets to keep alive. + limit?: number; + // When paths is configured, only the specified paths will be kept alive. + paths?: string[]; +} + +const OUTLET_LIMIT = 5; + +export default function KeepAliveOutlet(props: OutletProps) { if (!Activity) { throw new Error('`` now requires react experimental version. Please install it first.'); } const [outlets, setOutlets] = useState([]); const location = useLocation(); const outlet = useOutlet(); + const outletLimit = props.limit || OUTLET_LIMIT; + const keepAlivePaths = props.paths; + // Save the first outlet for SSR hydration. const outletRef = useRef({ key: location.key, pathname: location.pathname, outlet, }); - useEffect(() => { // If outlets is empty, save the first outlet for SSR hydration, // and should not call setOutlets to avoid re-render. if (outlets.length !== 0 || outletRef.current?.pathname !== location.pathname) { let currentOutlets = outletRef.current ? [outletRef.current] : outlets; + if (keepAlivePaths && keepAlivePaths.length > 0) { + currentOutlets = currentOutlets.filter(o => keepAlivePaths.includes(o.pathname)); + } const result = currentOutlets.some(o => o.pathname === location.pathname); if (!result) { setOutlets([ - // TODO: the max length of outlets should be configurable. ...currentOutlets, { key: location.key, pathname: location.pathname, outlet, }, - ]); + ].slice(-outletLimit)); outletRef.current = null; } } - }, [location.pathname, location.key, outlet, outlets]); + }, [location.pathname, location.key, outlet, outlets, outletLimit, keepAlivePaths]); // Render initail outlet for SSR hydration. const renderOutlets = outlets.length === 0 ? [outletRef.current] : outlets;