2.0.0 • Published 1 year ago

@654356282/react-keepalive v2.0.0

Weekly downloads
-
License
ISC
Repository
github
Last release
1 year ago

ReactKeepAlive

为组件提供 keepalive 能力,无数据断层!不操作 dom 节点!使用 suspense 作 keepalive!

缓存策略:优先使用 children 的 key 值作为缓存的 key,如果不存在 key 则使用 children 的 type

Keepalive Props

excludes: []|Regexp|(key: string|number)=>boolean: 传入不需要缓存的组件的key,或者可传入正则表达式或函数

includes: []|Regexp|(key: string|number)=>boolean: 传入需要换的的组件的key,或者可传入正则表达式或函数

Ref

type KeepAliveRef = {
  controller: {
    // 丢弃缓存的组件
    drop: (name: Key) => void;
  } | null;
};

Hooks

useActived: 组件从初次渲染或者从隐藏切换到显示时激活 useUnactived: 组件销毁或者从显示切换到隐藏时激活 useController: 获取refcontroller对象

usage

组件缓存

import { KeepAlive, useActived, useUnactived } from "@654356282/react-keepalive";
import React, { useState } from "react";

const Comp1 = () => {
  const [count, setCount] = useState(0);

  useActived(() => {
    console.log("Comp1 is actived");
  });

  useUnactived(() => {
    console.log("Comp1 is unactived");
  });

  return (
    <div>
      Comp1
      <button onClick={() => setCount(count + 1)}>+1</button>
    </div>
  );
};

const Comp2 = () => {
  const [count, setCount] = useState(0);

  useActived(() => {
    console.log("Comp2 is actived");
  });

  useUnactived(() => {
    console.log("Comp2 is unactived");
  });

  return (
    <div>
      Comp2
      <button onClick={() => setCount(count + 1)}>+1</button>
    </div>
  );
};

// 此时keepalive中缓存的key值为Comp1和Comp2
function App() {
  const [toggle, setToggle] = useState(false);

  return (
    <div>
      <KeepAlive>{toggle ? <Comp1 /> : <Comp2 />}</KeepAlive>
      <button onClick={() => setToggle(!toggle)}>change</button>
    </div>
  );
}

react-router集成,使用createBrowserRouter

import { ReactElement, useState } from "react";
import { KeepAlive, useActived, useUnactived } from "@654356282/react-keepalive";
import { RouterProvider, createBrowserRouter, NavLink } from "react-router-dom";
import React from "react";

function KeepAliveWrapper(props: { children: ReactElement }) {
  return <KeepAlive excludes={["/home"]}>{props.children}</KeepAlive>;
}

const router = createBrowserRouter([
  {
    path: "/",
    element: (
      <KeepAliveWrapper>
        <Root key="/" />
      </KeepAliveWrapper>
    ),
  },
  {
    path: "/home",
    element: (
      <KeepAliveWrapper>
        <Home key="/home" />
      </KeepAliveWrapper>
    ),
  },
]);

function Root() {
  const [count, setCount] = useState(0);

  useActived(() => {
    console.log("Root is actived");
  });

  useUnactived(() => {
    console.log("Root is unactived");
  });

  return (
    <div>
      <div>Root</div>
      <div>
        {count}
        <button onClick={() => setCount(count + 1)}>+1</button>
      </div>
      <NavLink to={"/home"}>跳转</NavLink>
    </div>
  );
}

function Home() {
  const [count, setCount] = useState(0);

  useActived(() => {
    console.log("Home is actived");
  });

  useUnactived(() => {
    console.log("Home is unactived");
  });

  return (
    <div>
      <div>Home</div>
      <div>
        {count}
        <button onClick={() => setCount(count + 1)}>+1</button>
      </div>
      <NavLink to={"/"} replace>
        跳转
      </NavLink>
    </div>
  );
}

export default function App() {
  return <RouterProvider router={router} />;
}

使用嵌套式路由

import React, { ReactElement, useState } from "react";
import {
  BrowserRouter,
  NavLink,
  Outlet,
  Route,
  Routes,
} from "react-router-dom";
import { KeepAlive, useActived, useUnactived } from "@654356282/react-keepalive";

function wrapKeepAlive(children: ReactElement) {
  return <KeepAlive includes={/^\/home.*/}>{children}</KeepAlive>;
}

const Home = () => {
  useActived(() => {
    console.log("home actived");
  });

  useUnactived(() => {
    console.log("home unactived");
  });
  const [count, setCount] = useState(0);

  return (
    <div>
      <div>home--{count}</div>
      <button onClick={() => setCount(count + 1)}>+1</button>
      <NavLink to="/user">跳转 user</NavLink>
      <Outlet />
    </div>
  );
};

const HomeSon = () => {
  const [count, setCount] = useState(0);

  useActived(() => {
    console.log("home son actived");
  });

  useUnactived(() => {
    console.log("home son unactived");
  });

  return (
    <div>
      <div>home son--{count}</div>
      <button onClick={() => setCount(count + 1)}>son + 1</button>
      <NavLink to="/user/son">跳转user son</NavLink>
    </div>
  );
};

const User = () => {
  const [count, setCount] = useState(0);
  useActived(() => {
    console.log("user actived");
  });

  useUnactived(() => {
    console.log("user unactived");
  });

  return (
    <div>
      <div>user--{count}</div>
      <button onClick={() => setCount(count + 1)}>+1</button>
      <NavLink to="/home">跳转 home</NavLink>
      <Outlet />
    </div>
  );
};

const UserSon = () => {
  const [count, setCount] = useState(0);

  useActived(() => {
    console.log("user son actived");
  });

  useUnactived(() => {
    console.log("user son unactived");
  });

  return (
    <div>
      <div>user son--{count}</div>
      <button onClick={() => setCount(count + 1)}>+1</button>
      <NavLink to="/home/son">跳转home son</NavLink>
    </div>
  );
};

const App = () => {
  return (
    <BrowserRouter>
      <Routes>
        <Route path="/home" element={wrapKeepAlive(<Home key="/home" />)}>
          <Route
            path="son"
            element={wrapKeepAlive(<HomeSon key="/home/son"></HomeSon>)}
          />
        </Route>
        <Route path="/user" element={wrapKeepAlive(<User key="/user" />)}>
          <Route
            path="son"
            element={wrapKeepAlive(<UserSon key="/user/son" />)}
          />
        </Route>
      </Routes>
    </BrowserRouter>
  );
};

export default App;

tips: 如果需要缓存子路由,请保证父级路由需要keepAlive

2.0.0

1 year ago

1.1.0

1 year ago

1.0.2

1 year ago

1.0.1

1 year ago

1.0.0

1 year ago