Skip to content

Instantly share code, notes, and snippets.

@ajitid
Last active January 12, 2023 15:36
Show Gist options
  • Save ajitid/142156b6387132dc55e07a2b24a6eaec to your computer and use it in GitHub Desktop.
Save ajitid/142156b6387132dc55e07a2b24a6eaec to your computer and use it in GitHub Desktop.
Keep alive routes

Hey, it does not passes route context so router's hooks and outlet component won't work. So this code, at least for now, is pretty useless.

Uses React Router v6

Usage

Before:

<Routes>
 <Route path="/" element={<Home />} />
 <Route path="/contacts" element={<Contacts />} />
</Routes>

After:

<AliveAbleRoutes>
 <Route path="/" element={<Home />} />
 <KeepAliveRoute path="/contacts" element={<Contacts />} />
</AliveAbleRoutes>
import React, { ReactElement, useState, useLayoutEffect } from 'react';
import { Routes, Route } from 'react-router-dom';
import type { RoutesProps, RouteProps } from 'react-router';
const AliveAbleRoutes = ({ children, ...props }: RoutesProps) => {
const routes = React.Children.toArray(children);
const keepAliveRoutes = routes.filter((route) => {
if (!React.isValidElement(route)) return false;
return route.type === KeepAliveRoute;
}) as ReactElement[];
const normalRoutes = routes.filter((route) => {
if (!React.isValidElement(route)) return false;
return route.type !== KeepAliveRoute;
}) as ReactElement[];
return (
<>
{keepAliveRoutes.map((route) => {
return (
<DisplayRoute key={route.key} {...route.props} routesProps={props} />
);
})}
<Routes {...props} children={normalRoutes} />
</>
);
};
interface DisplayRouteProps extends RouteProps {
routesProps: RoutesProps;
}
const DisplayRoute = ({
element,
routesProps,
...props
}: DisplayRouteProps) => {
const [show, setShow] = useState(false);
return (
<>
<div style={{ display: show ? 'unset' : 'none' }}>{element}</div>
<Routes {...routesProps}>
<Route
{...props}
element={<RouteMatchInformant onRouteMatchChange={setShow} />}
/>
</Routes>
</>
);
};
interface RouteMatchInformantProps {
onRouteMatchChange: (matches: boolean) => void;
}
const RouteMatchInformant = ({
onRouteMatchChange,
}: RouteMatchInformantProps) => {
useLayoutEffect(() => {
onRouteMatchChange(true);
return () => {
onRouteMatchChange(false);
};
}, [onRouteMatchChange]);
return null;
};
export const KeepAliveRoute = (props: RouteProps) => null;
export default AliveAbleRoutes;
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment