react实现汉堡_100行JavaScript代码在React中优雅的实现简单组件keep-Alive

bVbyiH3?w=699&h=401

React是近些年出现比较优秀的前端框架,它的设计思想,源码非常棒。

什么是状态保存?

假设有下述场景:

移动端中,用户访问了一个列表页,上拉浏览列表页的过程中,随着滚动高度逐渐增加,数据也将采用触底分页加载的形式逐步增加,列表页浏览到某个位置,用户看到了感兴趣的项目,点击查看其详情,进入详情页,从详情页退回列表页时,需要停留在离开列表页时的浏览位置上

类似的数据或场景还有已填写但未提交的表单、管理系统中可切换和可关闭的功能标签等,这类数据随着用户交互逐渐变化或增长,这里理解为状态,在交互过程中,因为某些原因需要临时离开交互场景,则需要对状态进行保存

在 React 中,我们通常会使用路由去管理不同的页面,而在切换页面时,路由将会卸载掉未匹配的页面组件,所以上述列表页例子中,当用户从详情页退回列表页时,会回到列表页顶部,因为列表页组件被路由卸载后重建了,状态被丢失

如何实现 React 中的状态保存

在Vue中,我们可以非常便捷地通过 标签实现状态的保存,该标签会缓存不活动的组件实例,而不是销毁它们

而在React 中并没有这个功能,曾经有人在官方提过功能issues,但官方认为这个功能容易造成内存泄露,表示暂时不考虑支持,所以我们需要自己想办法了

常见的解决方式:手动保存状态

手动保存状态,是比较常见的解决方式,可以配合React组件的componentWillUnmount生命周期通过redux之类的状态管理层对数据进行保存,通过componentDidMount周期进行数据恢复

在需要保存的状态较少时,这种方式可以比较快地实现我们所需功能,但在数据量大或者情况多变时,手动保存状态就会变成一件麻烦事了

作为程序员,当然是尽可能懒啦,为了不需要每次都关心如何对数据进行保存恢复,我们需要研究如何自动保存状态

最初的版本react-keep-alive

1c45ee868bc2ec946d9249e2cf38225f.png

1500行TypeScript代码在React中实现组件keep-alive 我的这篇文章对源码进行了解析,但是这个库存在断层现象,虽然可以缓存最后一次状态渲染结果,但是后面数据变化无法再进行数据驱动。而且是借助React.createPortal借助实现,我跟下面这个库的作者都觉得这是多余的,其实只需要抽取children属性,再封装一次HOC高阶组件即可。

总体来说,react-keep-alive这个库比较重,实现原理也不难,就是笨重,断层,源码跳来跳去,真的理清楚了就好

react-activation优雅的实现

效果实现:

63b905855e0e737793546a69922f6745.gif

6ce987e6f5b281ce6fa304b720af1f13.gif

庖丁解牛,源码解析

使用方式:开箱即用

import React, { useState } from 'react'

import { render } from 'react-dom'

import KeepAlive, { AliveScope } from './KeepAlive'

...

function App() {

const [show, setShow] = useState(true)

return (

setShow(show => !show)}>Toggle

无 KeepAlive

{show && }

有 KeepAlive

{show && (

)}

)

}

....

render(

,

document.getElementById('root')

)

注意 : 缓存的虚拟DOM元素会储存在AliveScope组件中,所以它不能被卸载

使用AliveScope配合KeepAlive即可达到缓存效果,类似react-keep-alive

首先我们看看AliveScope组件做了什么事情

export class AliveScope extends Component {

nodes = {}

state = {}

keep = (id, children) =>

new Promise(resolve =>

this.setState(

{

[id]: { id, children }

},

() => resolve(this.nodes[id])

)

)

render() {

return (

{this.props.children}

{Object.values(this.state).map(({ id, children }) => (

key={id}

ref={node => {

this.nodes[id] = node

}}

>

{children}

))}

)

}

}

它的源码只有几十行,很简单,这里的this.props.children是虚拟DOM,经过Babel编译和React处理,最终会转化成真实DOM节点渲染

逐步解析:

{this.props.children}

是这个组件的所有子元素,必须要渲染

使用React的Context API进行传递KEEP方法给所有的子孙组件,每次这个方法被调用,都会造成AliveScope组件重新渲染,进而刷新子组件,并且返回一个真实的DOM节点,这个真实的DOM节点就可以被直接DOM操作。

f56f2b0ab1d4f90b1f2a8fc48bbe85da.png

这张思维导图,可以很清楚的表示,我们的缓存实现方式,如果看不懂,慢慢往下看

KeepAlive组件的源码

import React, { Component, createContext } from 'react'

const { Provider, Consumer } = createContext()

const withScope = WrappedCompoennt => props => (

{keep => }

)

@withScope

class KeepAlive extends Component {

constructor(props) {

super(props)

this.init(props)

}

init = async ({ id, children, keep }) => {

const realContent = await keep(id, children)

this.placeholder.appendChild(realContent)

}

render() {

return (

ref={node => {

this.placeholder = node

}}

/>

)

}

}

export default KeepAlive

withScope是一个高阶组件,将KeepAlive组件传入,返回一个新的组件,这里使用了装饰器,@withScope.其实最终export default的是withScope(KeepAlive)

这里就是跟react-keep-alive的真正区别,withScope使用了context api捕获了传入的虚拟DOM节点,桥接了父组件以及KeepAlive组件的关联,一旦children属性改变,那么withScope被刷新,进而传入新的children属性给KeepAlive组件,导致数据驱动可以进行组件刷新

这又印证了那句话

在计算机的世界里,如果出现解决不了的问题,那就加一个中间层,如果还不行就加两个 --来自不知名码农Peter

eb99f55ca55b597aac9ba1237aa96906.png

这里按照代码运行逻辑,完整的解析了它的简单缓存机制实现,思路整体比较清晰,加上代码自己断点调试难度应该比较低,个人觉得这个库的设计和思想,都是不错的,值得推广,作者也是比较乐意解答问题。大家有问题可以在github上提问。

另外SegmentFault前端交流群还有名额,有需要的可以加我微信:CALASFxiaotan,里面大量小姐姐哦

欢迎关注微信公众号:前端巅峰

觉得不错记得点个赞哦~ 以后会有更多的源码解析

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
提供的源码资源涵盖了Java应用等多个领域,每个领域都包含了丰富的实例和项目。这些源码都是基于各自平台的最新技术和标准编写,确保了在对应环境下能够无缝运。同时,源码配备了详细的注释和文档,帮助用户快速理解代码结构和实现逻辑。 适用人群: 适合毕业设计、课程设计作业。这些源码资源特别适合大学生群体。无论你是计算机相关专业的学生,还是对其他领域编程感兴趣的学生,这些资源都能为你提供宝贵的学习和实践机会。通过学习和运这些源码,你可以掌握各平台开发的基础知识,提升编程能力和项目实战经验。 使用场景及目标: 在学习阶段,你可以利用这些源码资源进课程实践、课外项目或毕业设计。通过分析和运源码,你将深入了解各平台开发的技术细节和最佳实践,逐步培养起自己的项目开发和问题解决能力。此外,在求职或创业过程,具备跨平台开发能力的大学生将更具竞争力。 其他说明: 为了确保源码资源的可运性和易用性,特别注意了以下几点:首先,每份源码都提供了详细的运环境和依赖说明,确保用户能够轻松搭建起开发环境;其次,源码的注释和文档都非常完善,方便用户快速上手和理解代码;最后,我会定期更新这些源码资源,以适应各平台技术的最新发展和市场需求。 所有源码均经过严格测试,可以直接运,可以放心下载使用。有任何使用问题欢迎随时与博主沟通,第一时间进解答!

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值