Skip to content

Latest commit

 

History

History
350 lines (281 loc) · 8.96 KB

README.zh_CN.md

File metadata and controls

350 lines (281 loc) · 8.96 KB

keepalive-for-react logo

React KeepAlive 组件

一个类似Vue中keep-alive的React KeepAlive组件

English | 中文

NPM版本 NPM下载量

包信息

包名 版本 描述
keepalive-for-react NPM版本 核心keepalive功能
keepalive-for-react-router NPM版本 React Router集成

特性

  • 支持react-router-dom v6+ 或 react-router v7+
  • 支持React v16+ ~ v18+
  • 支持Suspense和懒加载导入
  • 支持错误边界
  • 支持自定义容器
  • 支持使用className activeinactive进行切换动画过渡
  • 简单实现,无需任何额外依赖和hack方式
  • 压缩后仅6KB大小

注意事项

  • 请勿使用 <React.StrictMode />,它在开发模式下无法与keepalive-for-react一起工作。因为它可能会导致一些意外行为。

  • 在路由中仅支持react-router-dom v6+

安装

npm install keepalive-for-react
yarn add keepalive-for-react
pnpm add keepalive-for-react

使用

配合react-router-dom v6+ 或 react-router v7+使用

  1. 安装react-router-dom v6+ 或 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. 在项目中使用KeepAlive
// v6+ [email protected]
// v7+ [email protected]
import KeepAliveRouteOutlet from "keepalive-for-react-router";

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

或者

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();

    // 确定哪个路由组件处于活动状态
    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>
    );
}

详情请参见 examples/react-router-dom-simple-starter

在StackBlitz中打开

在简单标签页中

npm install keepalive-for-react
const tabs = [
    {
        key: "tab1",
        label: "标签1",
        component: Tab1,
    },
    {
        key: "tab2",
        label: "标签2",
        component: Tab2,
    },
    {
        key: "tab3",
        label: "标签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>
    );
}

详情请参见 examples/simple-tabs-starter

在StackBlitz中打开

KeepAlive 属性

类型定义

interface KeepAliveProps {
    // 确定哪个组件处于活动状态
    activeCacheKey: string;
    children?: KeepAliveChildren;
    /**
     * 最大缓存数量 默认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;
    }>;
    /**
     * 过渡效果 默认false
     */
    transition?: boolean;

    /**
     * 使用view transition来过渡组件 默认false
     * @see https://developer.chrome.com/docs/web-platform/view-transitions/
     */
    viewTransition?: boolean;

    /**
     * 过渡时间 默认200ms
     */
    duration?: number;
    aliveRef?: RefObject<KeepAliveRef | undefined>;
    /**
     * 缓存节点最大存活时间 (秒)
     * @default 0 (无限制)
     */
    maxAliveTime?: number | MaxAliveConfig[];
}

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

Hooks

useEffectOnActive

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

useLayoutEffectOnActive

useLayoutEffectOnActive(
    () => {
        console.log("active");
    },
    [],
    false,
);
// 第三个参数是可选的,默认为false,
// 如果为true,表示在首次渲染时触发useLayoutEffect时会跳过回调

useKeepAliveContext

类型定义

interface KeepAliveContext {
    /**
     * 组件是否处于活动状态
     */
    active: boolean;
    /**
     * 刷新组件
     * @param {string} [cacheKey] - 组件的缓存键。如果未提供,将刷新当前缓存的组件。
     */
    refresh: (cacheKey?: string) => void;
    /**
     * 销毁组件
     * @param {string} [cacheKey] - 组件的缓存键,如果未提供,将销毁当前活动的缓存组件。
     */
    destroy: (cacheKey?: string | string[]) => Promise<void>;
    /**
     * 销毁所有组件
     */
    destroyAll: () => Promise<void>;
    /**
     * 销毁除提供的cacheKey外的其他组件
     * @param {string} [cacheKey] - 组件的缓存键。如果未提供,将销毁除当前活动缓存组件外的所有组件。
     */
    destroyOther: (cacheKey?: string) => Promise<void>;
    /**
     * 获取缓存节点
     */
    getCacheNodes: () => Array<CacheNode>;
}
const { active, refresh, destroy, getCacheNodes } = useKeepAliveContext();
// active 是一个布尔值,true表示活动,false表示非活动
// refresh 是一个函数,你可以调用它来刷新组件
// destroy 是一个函数,你可以调用它来销毁组件
// ...
// getCacheNodes 是一个函数,你可以调用它来获取缓存节点

useKeepAliveRef

类型定义

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 是一个 KeepAliveRef 对象

    // 你可以在 aliveRef.current 上调用 refresh 和 destroy
    aliveRef.current?.refresh();
    // 通常不需要手动调用 destroy,KeepAlive 会自动处理
    aliveRef.current?.destroy();

    return <KeepAlive aliveRef={aliveRef}>{/* ... */}</KeepAlive>;
}
// 或者
function AppRouter() {
    const aliveRef = useKeepAliveRef();
    // aliveRef.current 是一个 KeepAliveRef 对象

    // 你可以在 aliveRef.current 上调用 refresh 和 destroy
    aliveRef.current?.refresh();
    aliveRef.current?.destroy();
    return <KeepAliveRouteOutlet aliveRef={aliveRef} />;
}

开发

安装依赖

pnpm install

构建包

pnpm build

链接包到全局

pnpm link --global

在演示项目中测试

cd demo
pnpm link --global keepalive-for-react