React实现页面状态缓存(keep-alive)的示例代码

作者:状态漫游时间:2026-10-31 11:10:26浏览:501

本文介绍在React单页面应用中实现页面状态缓存的解决方案。针对路由跳转导致组件销毁、状态丢失的问题,对比了react-activation、umi-plugin-keep-alive及Offscreen API等方案。重点讲解如何配置react-activation实现路由级缓存,包括安装、Babel插件配置、KeepAlive组件包裹及路由isCache属性设置,并提供完整示例代码。

前言:

由于React和Vue均属于单页面应用(SPA),在路由切换时,前一个页面的组件会被销毁。然而,部分业务场景下需要保留页面状态,避免组件被销毁。

例如在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框架,由阿里开发,因此优先考虑使用。但查看文档后发现,它们基于react-activation,且作者建议关注后者。

前言:

umi-plugin-keep-alive的API说明:

如果你的项目使用的是Umi框架,可以使用umi-plugin-keep-alive(低版本Umi可能不支持)。例如Ant Design Pro、若依等基于Umi搭建的项目均可使用该插件。由于该插件与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。

yarn add react-activation
# or
npm install react-activation

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

{
  "plugins": [
    "react-activation/babel"
  ]
}

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

<KeepAlive cacheKey="UNIQUE_ID" />

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

官网示例:

// 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就是该路由需要缓存。

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

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

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

还可以手动清除缓存。

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使用文档

以上就是React实现页面状态缓存(keep-alive)的示例代码的详细内容,更多关于React页面状态缓存的资料请关注本站其它相关文章!

作者最新文章
相关文章
更多