npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

keepalive-for-react

v6.0.0

Published

A react <KeepAlive/> component like <keep-alive/> in vue

Readme

中文 | English

NPM version NPM downloads

Packages

| Package | Version | Description | | ----------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------- | ---------------------------- | | keepalive-for-react | NPM version | Core keepalive functionality | | keepalive-for-react-router | NPM version | React Router integration |

Features

  • Support react-router-dom v6+ or react-router v7+
  • Support React v16+ ~ v18+ (v19.2 Activity component support [v5.0.0])
  • 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
  • Support interrupt state effect when component is not active (v5.0.0)

Attention

  • Version Compatibility:

  • 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+ or react-router v7+

  1. install react-router-dom v6+ or react-router v7+
# v6+
npm install react-router-dom keepalive-for-react [email protected]
# v7+
npm install react-router keepalive-for-react [email protected]
  1. use KeepAlive in your project
// v6+ [email protected]
// v7+ [email protected]
import KeepAliveRouteOutlet from "keepalive-for-react-router";

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

or

import { useMemo } from "react";
// v6+
import { useLocation, useOutlet } from "react-router-dom";
// v7
// import { useLocation, useOutlet } from "react-router";
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;
    /**
     * use view transition to animate the component when switching tabs
     * @see https://developer.chrome.com/docs/web-platform/view-transitions/
     */
    viewTransition?: boolean;
    /**
     * transition duration default 200
     */
    duration?: number;
    aliveRef?: RefObject<KeepAliveRef | undefined | null>;
    /**
     * max alive time for cache node (second)
     * @default 0 (no limit)
     */
    maxAliveTime?: number | MaxAliveConfig[];
    /**
     * enable Activity component from react 19+
     * @default false
     * Activity component can improve performance
     * Attention: if enable Activity component, useEffect will trigger when the component is active
     */
    enableActivity?: boolean;
    customClassNames?: {
        active?: string;
        inactive?: string;
    };
}

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

Custom state class names

customClassNames customizes the active and inactive class names on cache nodes. It defaults to { active: "active", inactive: "inactive" }; omitted fields keep their defaults. Each value must be a single non-empty CSS class name.

<KeepAlive activeCacheKey={currentTab} transition customClassNames={{ active: "tab-active", inactive: "tab-inactive" }}>
    {children}
</KeepAlive>

Update your transition CSS selectors to match the custom names. cacheNodeClassName sets the cache node's base class independently of these state classes.

Hooks

useEffectOnActive

useEffectOnActive(() => {
    console.log("active");
}, []);

useLayoutEffectOnActive

useLayoutEffectOnActive(
    () => {
        console.log("active");
    },
    [],
    false,
);
// the third parameter is optional, default is false,
// if true, which means the callback will be skipped when the useLayoutEffect is triggered in first render

useEffectOnCreate

Run a callback only once when the component is first created (cached), and run the returned cleanup only when the component is destroyed from the cache. Unlike useEffect(fn, []), it will NOT re-run when the cached component is re-activated.

useEffectOnCreate(() => {
    console.log("component created");
    return () => {
        console.log("component destroyed");
    };
});

useLayoutEffectOnCreate

Same as useEffectOnCreate but uses useLayoutEffect internally. Useful when the create-time logic needs to run synchronously before the browser paints.

useLayoutEffectOnCreate(() => {
    console.log("component created (layout)");
    return () => {
        console.log("component destroyed (layout)");
    };
});

useKeepAliveContext

type definition

interface KeepAliveContext {
    /**
     * whether the component is active
     */
    active: boolean;
    /**
     * The key of this component's cache node, which may differ from the active node's key.
     */
    cacheKey: string;
    /**
     * 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, the cache node containing the calling 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, keep the cache node containing the calling component and destroy the others.
     */
    destroyOther: (cacheKey?: string) => Promise<void>;
    /**
     * get the cache nodes
     */
    getCacheNodes: () => Array<CacheNode>;
}
const { active, cacheKey, refresh, destroy, getCacheNodes } = useKeepAliveContext();
// cacheKey identifies this component's cache node
// 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