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