React中如何实现状态自动保存?
时间:2023-03-11 23:34:17
科技观察
什么是状态保存?假设如下场景:在移动端,用户访问列表页面。在向上滚动浏览列表页的过程中,随着滚动高度的逐渐增加,数据也会以逐页底部加载的形式逐渐增加。列表页浏览到某个位置,用户看到感兴趣的项目,点击查看其详情,进入详情页。从详情页返回列表页时,离开列表页时需要停留在浏览位置。未提交的表单、管理系统中可切换可关闭的功能标签等。这类数据随着用户交互逐渐变化或增长,在这里理解为状态。在交互过程中,由于某些原因需要暂时离开交互场景,需要在React中保存状态。我们通常使用路由来管理不同的页面。切换页面时,路由会卸载不匹配的页面组件。因此,在上面的列表页示例中,当用户从详情页选择返回列表页时,会返回到列表页的顶部,因为列表页组件被路由卸载后重新构建,并且状态丢失了。如何在Vue中保存React中的状态,我们可以很方便的通过[1]标签实现状态保存。此标记缓存非活动组件实例而不是销毁它们。React中没有这样的功能。官方曾有人提到过函数issues[2],但官方认为这个函数容易造成记忆。泄露了,说明暂时不考虑支持,所以需要找一个通用的解决方案:ManuallysavethestateManuallysavethestate是一个比较通用的方案,可以配合React组件的componentWillUnmount生命周期来传递状态管理层如redux通过componentDidMount循环保存数据和恢复数据。当需要保存的状态较少时,这种方式可以比较快速的实现我们需要的功能,但是当数据量较大或者情况发生变化时,手动保存的状态就会发生变化。作为程序员,当然是越懒越好。为了不用担心每次如何保存和恢复数据,我们需要研究如何通过路由自动保存状态来实现状态自动保存(通常使用react-router)由于React中状态的丢失是由卸载引起的路由切换时的组件,可以尝试从路由机制入手,改变路由组件的渲染行为。我们有以下几种方式来实现这个功能1.重写组件,请参考react-live-route[4]重写可以实现我们想要的功能,但是成本比较高,需要注意的是原创功能保存,并兼容多个react-router版本2.将路由库替换为react-keeper[5]完全替换路由方案是一件有风险的事情,需要慎重考虑3.3.基于component扩展已有的行为,可以参考react-router-cache-route[6]看了的源码,发现如果使用component或者render属性,route的去向无法避免不匹配时被卸载。使用children属性作为方法,我们有可能手动控制渲染行为,关键代码在这里https://github.com/ReactTraining/react-router/blob/master/packages/react-router/modules/Route.js#L41-L72//摘自Route组件中的render函数realTherenderingresultofif(children===undefined){...children=null;}}return({children&&!isEmptyChildren(children)//当children存在时,children会被用于渲染?children:props.match?component?React.createElement(component,props):render?render(props):null//使用render属性不能阻止组件的卸载:null//使用组件属性不能阻止组件的卸载);基于以上源码探索,我们可以扩展,将的不匹配行为从卸载调整为隐藏,如下{props=>(
)}上面是最简单的调整方法,在实际情况中,还需要考虑隐藏状态下match为null导致组件报错的问题,并且因为不再是组件卸载,所以不配合与TransitionGroup配合得很好,这使得过渡动画难以实现。使用react-router-cache-route[7],得到的效果大致如下图所示。上面探讨了通过路由自动保存状态的可能性,以及现有的实现,但毕竟不是真正纯粹的KeepAlive功能。接下来,我们尝试探索真实的KeepAlive函数的实现,模拟真实的
函数。以下是预期的用法show&&()}