react 实现页面状态缓存(keep-alive)

前言:

因为 react、vue都是单页面应用,路由跳转时,就会销毁上一个页面的组件。但是有些项目不想被销毁,想保存状态。

比如:h5项目跳转其他页面返回时,页面状态不丢失。设想一个 页面我滑倒了中间,然后跳转到 详情页然后 返回,之前的页面刷新了,回到顶部了肯定不行(搜索条件之类的消失了,滚动条回到顶部了)!

比如:pc端项目后台管理项目里点击时 打开一个页签,页签切换,状态页会丢失。每次切换页签都重新请求了接口。

解决方案:

方案调研:

经过我的调研:

我找到的 第三放库有:

react-activation

umi-plugin-keep-alive

umi-plugin-keep-alive-tabs

react-keepalive-router

react-router-cache-route

redux、dva等(状态共享插件)

react-keepalive-router、react-router-cache-route:

react-keepalive-router、react-router-cache-route 是个人开发的,github上issues里的建议也没及时回答。所以我就放弃了,没考虑。

Offscreen:

Offscreen是react 18.x出的实验性api,所以我也放弃了。可以看react Offscreen
不过 此api如果正式使用的话,应该是最好的选择。其原理就是 把页面 隐藏起来,不销毁组件树。其实其他 插件原理也是这样。

umi-plugin-keep-alive、umi-plugin-keep-alive-tabs:

umi-plugin-keep-alive、umi-plugin-keep-alive-tabs 是umi里的,是阿里开发的,优先考虑的就是这个,但看了 文档发现 它基于 react-activation。而且 作者也让关注 。

umi-plugin-keep-alive api

其实 如果你项目是 umi的话 用 umi-plugin-keep-alive也可以(低版本umi可能不行)。antd-pro

若依等等基于umi搭建的库都可以使用umi-plugin-keep-alive。这个插件 和umi绑定,所以我也放弃了,但应该也可以单独使用(我没试过)。

redux等状态共享插件,需要项目搭建时就使用,原理就是,页面里不写 useState和state全都放到 store里。然后对整个store缓存。每次进入页面 判断一下有缓存就走缓存,没有重新请求。像redux之类的都有持久化插件,配合持久化插件就很容易实现。缺点是繁琐,且破坏了 不优雅,页面里不能写状态。而且 还要额外 记录滚动条的位置。

react-activation:

所以综上我选择了 react-activation 它是路由级别的缓存。

react-activation基础使用步骤及配置:

React Activation 仅支持 React 16 及以上版本

注意

1.请勿使用 <React.StrictMode />

2.(React v18+)不要使用 ReactDOMClient.createRoot ,使用 ReactDOM.render 代替, https://github.com/CJY0208/react-activation/issues/225#issuecomment-1311136388

1.安装 react-activation

bash 复制代码
yarn add react-activation
# or
npm install react-activation

(可选,推荐)在 .babelrc 中添加 react-activation/babel 插件

该插件在编译过程中为每个JSX元素添加了一个 _nk 属性,以帮助 react-activation 运行时根据 react-node-key 的渲染位置生成唯一的标识符。

javascript 复制代码
{
  "plugins": [
    "react-activation/babel"
  ]
}

如果不想使用Babel,建议每个 声明一个全局唯一不变的 cacheKey 属性,以保证该高速缓存的稳定性,如下所示:

javascript 复制代码
<KeepAlive cacheKey="UNIQUE_ID" />

2.import KeepAlive 然后包裹要缓存的组件 或者元素。

官网示例:

javascript 复制代码
// App.js

import React, { useState } from 'react'
import KeepAlive from 'react-activation'

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

  return (
    <div>
      <p>count: {count}</p>
      <button onClick={() => setCount(count => count + 1)}>Add</button>
    </div>
  )
}

function App() {
  const [show, setShow] = useState(true)

  return (
    <div>
      <button onClick={() => setShow(show => !show)}>Toggle</button>
      {show && (
        <KeepAlive>
          <Counter />
        </KeepAlive>
      )}
    </div>
  )
}

export default App

3.将 外层放置在不会卸载的位置,通常在应用入口处

配合路由使用react-activation

1.isCache是自定义的属性,用来标识是否 缓存。true就是改路由需要缓存。

javascript 复制代码
  {
    path: "/",
    component: <Initial />,
    title: "主页",
    name: "initPage",
    isCache: true,
    cacheKey: "home",
  }

路由配置可以参考:
react create-react-app v5 配置路由(报错及注意事项)

App.js 入口文件 或者 路由配置页面里 封装一层 根据 isCache值来确定是否使用 keepAlive包裹。如下:

javascript 复制代码
import React from "react";
import { BrowserRouter, Routes, Route, HashRouter } from "react-router-dom";
import routes from "./routes.js";
import KeepAlive from "react-activation";
// 封装一层 专门负责显示页面标题
const DomTitle = ({ route }) => {
  const { title, component, isCache ,cacheKey,name} = route;
  document.title = title;
  if (isCache) {
    return <KeepAlive cacheKey={cacheKey} name={name}>{component}</KeepAlive>;
  }
  return <>{component}</>;
};
const App = () => {
  return (
    <HashRouter>
      <Routes>
        {routes.map((route) => (
          <Route
            key={route.path}
            path={route.path}
            //element={route.component   }
            // 专门负责显示页面标题
            element={<DomTitle route={route} />}
          />
        ))}
      </Routes>
    </HashRouter>
  );
};

还可以手动清除缓存

javascript 复制代码
import {
  useActivate,
  useUnactivate,
  withActivation,
  withAliveScope,
  useAliveController,
} from "react-activation";
 const { drop, dropScope, clear, getCachingNodes } = useAliveController();
   console.log(getCachingNodes(), "缓存节点");
    //drop("homePage"); // 手动关闭某个页面
    // dropScope("detailPage");
    dropScope("homePage");  // 参数就是上面定义的  cacheKey

还需要 将 外层放置在不会卸载的位置,通常在应用入口处 我的项目时create-react-app 是index.js。

具体 api使用方法和注意事项请看:

具体api可以看(如果 github打不开可以看npm的,npm是英文的,可以用edge浏览器 翻译一下):
react-activation github 使用文档
react-activation npm 使用文档

相关推荐
也无晴也无风雨32 分钟前
深入剖析输入URL按下回车,浏览器做了什么
前端·后端·计算机网络
Martin -Tang1 小时前
Vue 3 中,ref 和 reactive的区别
前端·javascript·vue.js
FakeOccupational3 小时前
nodejs 020: React语法规则 props和state
前端·javascript·react.js
小牛itbull3 小时前
ReactPress:构建高效、灵活、可扩展的开源发布平台
react.js·开源·reactpress
放逐者-保持本心,方可放逐3 小时前
react 组件应用
开发语言·前端·javascript·react.js·前端框架
曹天骄4 小时前
next中服务端组件共享接口数据
前端·javascript·react.js
阮少年、4 小时前
java后台生成模拟聊天截图并返回给前端
java·开发语言·前端
Wlq04155 小时前
分布式技术缓存技术
分布式·缓存
郝晨妤5 小时前
鸿蒙ArkTS和TS有什么区别?
前端·javascript·typescript·鸿蒙
AvatarGiser6 小时前
《ElementPlus 与 ElementUI 差异集合》Icon 图标 More 差异说明
前端·vue.js·elementui