天天看點

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的路由會被一直儲存,别忘了在适當的時候清除緩存

4.跳到外部頁面或者用window.location.href 跳轉本項目的頁面再傳回都是重新挂載頁面,沒有緩存

具體使用方法詳見文檔,作者寫的很細https://github.com/CJY0208/react-activation/blob/master/README_CN.md