Releases: irychen/keepalive-for-react
Releases · irychen/keepalive-for-react
v3.0.0
KeepAlive for React
A React KeepAlive component like keep-alive in vue
中文 | English
Features
- Support react-router-dom v6+
- Support React v16+ ~ v18+
- Support Suspense and Lazy import
- Support ErrorBoundary
- Support Custom Container
- Support Switching Animation Transition with className
active
andinactive
- Simply implement, without any extra dependencies and hacking ways
Attention
-
DO NOT use <React.StrictMode />, it CANNOT work with keepalive-for-react in development mode. because it can lead to
some unexpected behavior when you use keepalive-for-react's useOnActive hook. -
In Router only support react-router-dom v6+
Install
npm install keepalive-for-react
yarn add keepalive-for-react
pnpm add keepalive-for-react
Usage
in react-router-dom v6+
- install react-router-dom v6+
npm install react-router-dom keepalive-for-react
- use KeepAlive in your project
import { KeepAliveRouteOutlet } from "keepalive-for-react";
function Layout() {
return (
<div className="layout">
<KeepAliveRouteOutlet />
</div>
);
}
details see examples/react-router-dom-simple-starter
in simple tabs
npm install keepalive-for-react
const tabs = [
{
key: "tab1",
label: "Tab 1",
component: Tab1,
},
{
key: "tab2",
label: "Tab 2",
component: Tab2,
},
{
key: "tab3",
label: "Tab 3",
component: Tab3,
},
];
function App() {
const [currentTab, setCurrentTab] = useState<string>("tab1");
const tab = useMemo(() => {
return tabs.find(tab => tab.key === currentTab);
}, [currentTab]);
return (
<div>
{/* ... */}
<KeepAlive transition={true} activeCacheKey={currentTab} exclude={["tab3"]}>
{tab && <tab.component />}
</KeepAlive>
</div>
);
}
details see examples/simple-tabs-starter
KeepAlive Props
type definition
interface KeepAliveProps {
// determine which component to is active
activeCacheKey: string;
children?: KeepAliveChildren;
/**
* max cache count default 10
*/
max?: number;
exclude?: Array<string | RegExp> | string | RegExp;
include?: Array<string | RegExp> | string | RegExp;
onBeforeActive?: (activeCacheKey: string) => void;
customContainerRef?: RefObject<HTMLDivElement>;
cacheNodeClassName?: string;
containerClassName?: string;
errorElement?: ComponentType<{
children: ReactNode;
}>;
/**
* transition default false
*/
transition?: boolean;
/**
* transition duration default 200
*/
duration?: number;
aliveRef?: RefObject<KeepAliveRef | undefined>;
}
Hooks
useEffectOnActive
useEffectOnActive(() => {
console.log("active");
}, []);
useLayoutEffectOnActive
useLayoutEffectOnActive(
() => {
console.log("active");
},
[],
false,
);
// the third parameter is optional, default is true,
// which means the callback will be skipped when the useLayoutEffect is triggered in first render
useKeepAliveContext
type definition
interface KeepAliveContext {
/**
* whether the component is active
*/
active: boolean;
/**
* refresh the component
* @param cacheKey - the cache key of the component,
* if not provided, current active cached component will be refreshed
*/
refresh: (cacheKey?: string) => void;
}
const { active, refresh } = useKeepAliveContext();
// active is a boolean, true is active, false is inactive
// refresh is a function, you can call it to refresh the component
useKeepaliveRef
type definition
interface KeepAliveRef {
refresh: (cacheKey?: string) => void;
destroy: (cacheKey: string) => Promise<void>;
}
function App() {
const aliveRef = useKeepaliveRef();
// aliveRef.current is a KeepAliveRef object
// you can call refresh and destroy on aliveRef.current
aliveRef.current?.refresh();
// it is not necessary to call destroy manually, KeepAlive will handle it automatically
aliveRef.current?.destroy();
return <KeepAlive aliveRef={aliveRef}>{/* ... */}</KeepAlive>;
}
// or
function AppRouter() {
const aliveRef = useKeepaliveRef();
// aliveRef.current is a KeepAliveRef object
// you can call refresh and destroy on aliveRef.current
aliveRef.current?.refresh();
aliveRef.current?.destroy();
return <KeepAliveRouteOutlet aliveRef={aliveRef} />;
}
Development
install dependencies
pnpm install
build package
pnpm build
link package to global
pnpm link --global
test in demo project
cd demo
pnpm link --global keepalive-for-react
v2.0.12
New Feature in v2.0.12
Now, you can refresh you cached component !!!
in KeepAlive aliveRef
import { useKeepaliveRef } from "keepalive-for-react"
function Example() {
const aliveRef = useKeepaliveRef()
function refresh(){
aliveRef.current?.refresh() // default refresh current showing cached component without the name param
// aliveRef.current?.refresh("your refresh component name")
}
// ...
return <KeepAlive aliveRef={aliveRef} >
...
</KeepAlive>
}
in cached component
import {useKeepAliveContext} from 'keepalive-for-react';
function CachedComponent() {
const { refresh } = useKeepAliveContext();
// refresh: (name?: string) => void, refresh the component same as `aliveRef.current?.refresh()`
}
v2.0.6
New Release: Version v2.0.6
Introducing new hooks useEffectOnActive, useLayoutEffectOnActive
/**
* a hook that executes a callback function when the active state of the cache component changes.
* The callback can optionally return a cleanup function that will be executed on component unmount or before the callback is executed again.
*
* @param cb A callback function to be executed when the active state changes. It receives the current active state as a parameter. If it returns a function, that function will be used as a cleanup callback.
* @param skipMount If true, the callback (and potentially its cleanup) is not executed on the initial component mount. Defaults to false.
* @param deps Dependencies to be passed to the useEffect hook.
*/
export const useEffectOnActive = (cb: (active: boolean) => void | (() => void), skipMount = false, deps: DependencyList): void => {
const { active } = useCacheComponentContext()
const isMount = useRef<boolean>(false)
useEffect(() => {
if (skipMount && !isMount.current) {
isMount.current = true
return
}
const destroyCb = cb(active)
return () => {
if (isFn(destroyCb)) {
destroyCb()
}
}
}, [active, ...deps])
}
/**
* @name useLayoutEffectOnActive
* a hook that executes a callback function when the active state of the cache component changes.
* The callback can optionally return a cleanup function that will be executed on component unmount or before the callback is executed again.
*
* @param cb A callback function to be executed when the active state changes. It receives the current active state as a parameter. If it returns a function, that function will be used as a cleanup callback.
* @param skipMount If true, the callback (and potentially its cleanup) is not executed on the initial component mount. Defaults to false.
* @param deps Dependencies to be passed to the useLayoutEffect hook.
*/
export const useLayoutEffectOnActive = (cb: (active: boolean) => void | (() => void), skipMount = false, deps: DependencyList): void => {
const { active } = useCacheComponentContext()
const isMount = useRef<boolean>(false)
useLayoutEffect(() => {
if (skipMount && !isMount.current) {
isMount.current = true
return
}
const destroyCb = cb(active)
return () => {
if (isFn(destroyCb)) {
destroyCb()
}
}
}, [active, ...deps])
}
v2.0.5
New Release: Version v2.0.5
Introducing new hooks:
useKeepaliveRef
type KeepAliveRef = {
getCaches: () => Array<CacheNode>
removeCache: (name: string) => void
cleanAllCache: () => void
cleanOtherCache: () => void
}
import { useKeepaliveRef } from "keepalive-for-react"
function Example() {
const aliveRef = useKeepaliveRef()
function clean(){
aliveRef.current?.cleanAllCache()
}
// ...
return <KeepAlive aliveRef={aliveRef} >
...
</KeepAlive>
}
v2.0.0
New Release: Version v2.0.0
Introducing new hooks:
useOnActive
useKeepAliveContext
Improvements:
- The
useOnActive
hook no longer requires thedomRef
parameter. useKeepAliveContext
now allows you to access the active state of the cached component and provides adestroy
method to clear the component's cache directly.