前言:
因为 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基础使用步骤及配置:
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
配合路由使用react-activation
1.isCache是自定义的属性,用来标识是否 缓存。true就是改路由需要缓存。
{ path: "/", component: <Initial />, title: "主页", name: "initPage", isCache: true, cacheKey: "home", }
路由配置可以参考:
react create-react-app v5 配置路由(报错及注意事项)
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
具体 api使用方法和注意事项请看:
具体api可以看(如果 github打不开可以看npm的,npm是英文的,可以用edge浏览器 翻译一下):
react-activation github 使用文档
react-activation npm 使用文档