Skip to content
This repository has been archived by the owner on May 9, 2020. It is now read-only.

React 中的状态自动保存(keep-alive) #111

Closed
chenbin92 opened this issue Mar 13, 2020 · 1 comment
Closed

React 中的状态自动保存(keep-alive) #111

chenbin92 opened this issue Mar 13, 2020 · 1 comment
Assignees
Labels
discussion Further information is requested

Comments

@chenbin92
Copy link
Contributor

chenbin92 commented Mar 13, 2020

问题背景

在 React 中通常会使用 react-router 去管理不同的页面切换,通过监听路由的变化匹配到对应的路由组件进行渲染,而未匹配到的组件将会被卸载, 这意味着组件被卸载之后其状态丢失

但在某些场景下,我们希望切换路由时还能保留组件的状态不被丢失,在下次展示时进行恢复,如:

场景一:

当用户在列表页面进入详情页面后,缓存列表页面的状态,当从详情页面返回列表页面时,能恢复到上次的状态(位置状态)。

场景二:

当用户在填写表单但未提交时、可能因为某些原因需要临时离开当前页面,当从其他页面返回表单页面时,能恢复用户填写的表单信息(数据状态)。

keep-alive 简介

什么是 keep-alive?

将组件保存在内存中,而不是卸载以及重新创建,避免重新渲染。也就是所谓的组件缓存。

  • 通过 keep-alive 可以保存当前页面的数据、状态、滚动条位置及渲染内容。当切换到对应页面时,被保存的页面将直接被渲染,还原为切换前的内容。

  • 被 keep-alive 包含的组件不会被再次初始化,也就意味着不会重走生命周期函数,但是有时候是希望我们缓存的组件可以能够再次进行渲染,因此被包含在 keep-alive 中创建的组件,通常会多出两个生命周期的钩子: activateddeactivated

  • activated:当 keep-alive 包含的组件再次渲染的时候触发
  • deactivated:当 keep-alive 包含的组件销毁的时候触发

在 React 中使用 keep-alive ?

在 React 中并没有 keep-alive 的概念,该概念来源于 Vue 提供的 keep-alive 功能。因此也有人在 facebook/react/issues/12039 中询问 React 是否能支持类似 Vue keep-alive 的功能。从 issue 看没有支持的计划, Dan 给出的说法是可以通过类似 style={{display: visible ? 'block' : 'none'}} 的思路,但不认为 keep-alive 是一个好的功能,以及可能会存在内存泄漏等。但强大的 React 社区肯定不会善罢甘休,也有了相关的实现。

在 React 实现 keep-alive

手动保存状态

手动保存状态即通过 React 提供的 componentWillUnmount 生命周期通过 redux 之类的状态管理库对数据进行保存,通过 componentDidMount 生命周期进行数据恢复,这也是目前最常见的解决方式,这里不展开讨论。

通过路由实现状态保存

由于状态丢失的主要原因是由于路由切换时导致组件被卸载,如果是这样,是否只需要保证组件不被卸载,或者在组件卸载之前将数据状态保存就可以解决我们的问题了,事实上目前社区的相关实现也正是这样。

核心思路:路由匹配 -> 组件渲染 -> 切换路由 -> 组件卸载 => 路由匹配 -> 组件渲染 -> 切换路由 -> 组件隐藏

社区方案对比:

库/功能 react-keep-alive react-keeper react-router-cache-route react-activation
实现思路 将 KeepAlive 的组件藏于其 Provider 中,保证其不会被卸载 - 基于 react-router 完全实现一个自定义的路由库 改写 react-router 库的 Route 组件,控制渲染行为,使其不被卸载 同 react-keep-alive
GitHub star 407 708 474 217
NPM download < 300 < 200 ~ 3k < 150
使用方式 KeepLive CacheLink CacheRoute、CacheSwitch KeepAlive
Class 生命周期 componentDidActivate componentWillUnactivate - componentDidCache componentDidRecover componentDidActivate componentWillUnactivate
Function 生命周期 useKeepAliveEffect - - useActivate useUnactivate
恢复滚动位置 支持 支持 支持 支持
缓存控制 支持 - 支持(不友好) 支持
总结 ★★★★ ★★ ★★ ★★★★

主要实现思路:

详见代码

在 icejs 中使用 keep-alive

TODO

小结

keep-alive 作为状态保存的一种实现方式,在某些场景如列表位置恢复,表单状态保存等非常有用,且无需重复渲染组件,是一种很好的选择。但当项目和数据复杂的情况下,需要合理使用 keep-alive 进行状态保存,以及数据的自动清理等。

相关链接:

@chenbin92 chenbin92 added the good first issue Good for newcomers label Mar 13, 2020
@chenbin92 chenbin92 self-assigned this Mar 13, 2020
@chenbin92 chenbin92 changed the title React 中的状态自动保存(KeepAlive) React 中的状态自动保存(keep-alive) Mar 13, 2020
@chenbin92 chenbin92 added discussion Further information is requested and removed good first issue Good for newcomers labels Mar 13, 2020
@chenbin92 chenbin92 modified the milestone: 03.16 ~ 03.20 Mar 16, 2020
@chenbin92 chenbin92 modified the milestone: 04.20 ~ 04.24 Apr 20, 2020
@chenbin92
Copy link
Contributor Author

chenbin92 commented May 8, 2020

结论,keep-alive 在 React 中使用场景和诉求相对较少,且有诸多方案可以满足其功能,icejs 中暂不支持

Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
discussion Further information is requested
Projects
None yet
Development

No branches or pull requests

1 participant