Skip to content

Commit

Permalink
Feat: support props for KeepAliveOutlet (#6819)
Browse files Browse the repository at this point in the history
* feat: support props for KeepAliveOutlet

* fix: lint warning

* fix: lint
  • Loading branch information
ClarkXia authored Mar 11, 2024
1 parent 886c4de commit ba811d7
Show file tree
Hide file tree
Showing 3 changed files with 24 additions and 6 deletions.
5 changes: 5 additions & 0 deletions .changeset/brave-items-cover.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
'@ice/runtime': patch
---

feat: support props for KeepAliveOutlet
2 changes: 1 addition & 1 deletion examples/with-keep-alive/src/pages/layout.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ export default function Layout() {
return (
<div>
<h2>Layout</h2>
<KeepAliveOutlet />
<KeepAliveOutlet limit={2} paths={['/home']} />
</div>
);
}
23 changes: 18 additions & 5 deletions packages/runtime/src/KeepAliveOutlet.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -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('`<KeepAliveOutlet />` now requires react experimental version. Please install it first.');
}
const [outlets, setOutlets] = useState<ActivityItem[]>([]);
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;
Expand Down

0 comments on commit ba811d7

Please sign in to comment.