React 中保存页面状态/在react中实现vue的keep-alive/React Activation

1.背景
用户访问了一个列表页,点击查进入详情页,从详情页退回列表页时,需要停留在离开列表页时的浏览位置上
在 React 中,我们通常会使用路由去管理不同的页面,而在切换页面时,路由将会卸载掉未匹配的页面组件,所以上述列表页例子中,当用户从详情页退回列表页时,会回到列表页顶部,因为列表页组件被路由卸载后重建了,状态被丢失。

2.常见的解决方式
(1)手动保存状态:配合 React 组件的 componentWillUnmount 生命周期通过dva、 redux 之类的数据流管理工具对数据进行保存,通过 componentDidMount 周期进行数据恢复。这种方法需要每次手动保存与恢复数据,并且像我们自己封装的列表组件,数据的请求和渲染都是在组件上进行的,这就导致在项目没办法保存与恢复数据。
(2)通过样式控制:列表和详情页写在同一个页面上,通过样式来控制组件的显示与隐藏。这种方法代码改动大并且体验不好。

3.自动保存状态
(1)常用*分析

组件
react-live-route 实现成本也比较高,需要注意对原始 功能的保存,以及多个 react-router 版本的兼容
react-keeper 完全替换掉路由方案是一个风险较大的事情,需要较为慎重地考虑
react-keep-alive 真实 KeepAlive 功能的实现
react-router-cache-route 由于不再是组件卸载,所以和 TransitionGroup 配合得不好,导致转场动画难以实现
react-activation 其 children 属性抽取出来,渲染到一个不会被卸载的组件内

(2)基于我们是配置式路由、业务代码改动最小以及组件所提供的能力,最后选择了react-activation。

import React, { Component } from 'react';
import KeepAlive, { withActivation } from 'react-activation';
import CachePage from './keepalive';

@CachePage
@withActivation
class Test extends Component {
  constructor(props) {
    super(props);
    this.state = {
      datalist: [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25,26, 27, 28, 29, 30],
    };
  }
  // 类组件要配合withActivation装饰器,才能使用componentDidActivat与componentWillUnactivate 对应激活与缓存两的生命周期
  // 函数组件可直接使用useActivate 与 useUnactivate hooks 钩子
  componentDidActivate() {
    console.log('激活页面——componentDidActivate')
  }
  componentWillUnactivate() {
    console.log('缓存页面——componentWillUnactivate')
  }
  render() {
    const { datalist } = this.state;
    return (
      <div>
        {datalist.map((item) => {
          return (
            <p key={item}>test——{item}</p>
          );
        })}
      </div>
    );
  }
}
export default Test;

/** keepalive.js **/
import React from 'react';
import KeepAlive from 'react-activation';
const CachePage = WrapperComponent => props => {
  const { location:{ pathname, search } } = props;
  return (
    <KeepAlive name={pathname} id={`${pathname}${search}`} when saveScrollPosition='screen'>
      <WrapperComponent {...props} />
    </KeepAlive>
  );
};
export default CachePage;

注:
1.KeepAlive没法作用到状态管理。同一个路由参数不同的页面, id不同虽然页面会多份缓存,但是如果页面数据有用model管理会造成数据错乱,因为缓存的只是页面而状态管理里面的数据变了就变了。
解决方法:可以在 model管理的数据注入进来的时候,不直接使用,可以是转成组件的 state,这样就可以跟着 KeepAlive 的状态走了。
2.KeepAlive 内部的组件才能响应缓存生命周期
3.when为true的路由会被一直保存,别忘了在适当的时候清除缓存

具体使用方法详见文档,作者写的很细https://github.com/CJY0208/react-activation/blob/master/README_CN.md

上一篇:IntelliJ IDEA配置


下一篇:nginx---keepalive_timeout timeout,和上传限制