keepalive-for-react
TypeScript icon, indicating that this package has built-in type declarations

3.0.7 • Public • Published

keepalive-for-react logo

KeepAlive for React

A React KeepAlive component like keep-alive in vue

中文 | English

NPM version NPM downloads

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 and inactive
  • Simply implement, without any extra dependencies and hacking ways
  • Only 6KB minified size

Attention

  • DO NOT use <React.StrictMode />, it CANNOT work with keepalive-for-react in development mode. because it can lead to some unexpected behavior.

  • 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+

  1. install react-router-dom v6+
npm install react-router-dom keepalive-for-react
  1. use KeepAlive in your project
import { KeepAliveRouteOutlet } from "keepalive-for-react";

function Layout() {
    return (
        <div className="layout">
            <KeepAliveRouteOutlet />
        </div>
    );
}

or

import { useMemo } from "react";
import { useLocation } from "react-router-dom";
import { KeepAlive, useKeepAliveRef } from "keepalive-for-react";

function Layout() {
    const location = useLocation();
    const aliveRef = useKeepAliveRef();

    const outlet = useOutlet();

    // determine which route component to is active
    const currentCacheKey = useMemo(() => {
        return location.pathname + location.search;
    }, [location.pathname, location.search]);

    return (
        <div className="layout">
            <MemoizedScrollTop>
                <KeepAlive transition aliveRef={aliveRef} activeCacheKey={currentCacheKey} max={18}>
                    <Suspense fallback={<LoadingArea />}>
                        <SpreadArea>{outlet}</SpreadArea>
                    </Suspense>
                </KeepAlive>
            </MemoizedScrollTop>
        </div>
    );
}

details see examples/react-router-dom-simple-starter

Open in StackBlitz

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

Open in StackBlitz

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>;
    /**
     * max alive time for cache node (second)
     * @default 0 (no limit)
     */
    maxAliveTime?: number | MaxAliveConfig[];
}

interface MaxAliveConfig {
    match: string | RegExp;
    expire: number;
}

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 {string} [cacheKey] - The cache key of the component. If not provided, the current cached component will be refreshed.
     */
    refresh: (cacheKey?: string) => void;
    /**
     * destroy the component
     * @param {string} [cacheKey] - the cache key of the component, if not provided, current active cached component will be destroyed
     */
    destroy: (cacheKey?: string | string[]) => Promise<void>;
    /**
     * destroy all components
     */
    destroyAll: () => Promise<void>;
    /**
     * destroy other components except the provided cacheKey
     * @param {string} [cacheKey] - The cache key of the component. If not provided, destroy all components except the current active cached component.
     */
    destroyOther: (cacheKey?: string) => Promise<void>;
    /**
     * get the cache nodes
     */
    getCacheNodes: () => Array<CacheNode>;
}
const { active, refresh, destroy, getCacheNodes } = useKeepAliveContext();
// active is a boolean, true is active, false is inactive
// refresh is a function, you can call it to refresh the component
// destroy is a function, you can call it to destroy the component
// ...
// getCacheNodes is a function, you can call it to get the cache nodes

useKeepAliveRef

type definition

interface KeepAliveRef {
    refresh: (cacheKey?: string) => void;
    destroy: (cacheKey?: string | string[]) => Promise<void>;
    destroyAll: () => Promise<void>;
    destroyOther: (cacheKey?: string) => Promise<void>;
    getCacheNodes: () => Array<CacheNode>;
}
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

Versions

Current Tags

VersionDownloads (Last 7 Days)Tag
3.0.7323latest

Version History

VersionDownloads (Last 7 Days)Published
3.0.7323
3.0.6195
3.0.513
3.0.414
3.0.30
3.0.232
3.0.13
3.0.00
2.0.1930
2.0.184
2.0.171
2.0.160
2.0.150
2.0.140
2.0.130
2.0.1212
2.0.110
2.0.102
2.0.93
2.0.812
2.0.72
2.0.68
2.0.50
2.0.40
2.0.30
2.0.20
2.0.10
2.0.00
1.0.224
1.0.210
1.0.200
1.0.193
1.0.180
1.0.170
1.0.160
1.0.150
1.0.140
1.0.130
1.0.121
1.0.110
1.0.100
1.0.90
1.0.80
1.0.7-00
1.0.70
1.0.60
1.0.50
1.0.41
1.0.31
1.0.21
1.0.11
1.0.01

Package Sidebar

Install

npm i keepalive-for-react

Weekly Downloads

667

Version

3.0.7

License

MIT

Unpacked Size

69.4 kB

Total Files

20

Last publish

Collaborators

  • wongyichen