图解React Diff算法及新架构Fiber-阿里云开发者社区

开发者社区> 人工智能> 正文

图解React Diff算法及新架构Fiber

简介: 阿里云前端工程师靖鑫带来了React高阶组件在业务场景中的应用。首先从高阶组件的思想开始谈起,帮助我们灵活管理代码,介绍了简单的HOC示例、传递参数的HOC示例、反向继承HOC,进而讲述了HOC库recompose,然后通过图解重点说明了DOM DIFF算法,最后对新架构Fiber进行了简要介绍。

阿里云前端工程师靖鑫带来了React高阶组件在业务场景中的应用。首先从高阶组件的思想开始谈起,帮助我们灵活管理代码,介绍了简单的HOC示例、传递参数的HOC示例、反向继承HOC,进而讲述了HOC库recompose,然后通过图解重点说明了DOM DIFF算法,最后对新架构Fiber进行了简要介绍。


数十款阿里云产品限时折扣中,赶快点击这里,领券开始云上实践吧!

直播视频精彩回顾

以下是精彩视频内容整理:

什么是高阶组件?

所谓高级组件本质上就是一个函数,接收一个组件后返回另外一个新的组件,这么做的意图就是为了增强(enhance),比如装饰、增添行为、增添逻辑等,都可以放在高阶组件中,高阶组件是一种可以增强组件的能力。

最简单的HOC示例

ac076ff9347e966af26d740e77dddf1b73b4e5ba

如图所示,使用装饰器方式来使用,声明一个函数,定义一个高阶组件,给目标组件包裹一层样式。接收一个组件,返回一个函数式组件props,将props全部解构传递给wrappedcomponent,高阶组件一定不可以影响原来的业务。在此基础上,我们在外面增加一些能力,比如在被包裹的组件外围,由一个card的dom元素包裹在一起。

传递参数的HOC示例

808404938cfc12629b6e43a59ebda784e1820896

首先设置参数,生成特定的HOC,再传递给目标组件使用。定义一个stylefactory方法,返回高阶组件,而不是组件。在高阶组件的前一步做了一层处理,利用闭包思想,它的入参是classname,返回的高阶组件一直内嵌classname。

反向继承HOC

00c34027b89082d22c1b99b21cf504194b1b68bb

前两种高阶组件的特点是不会修改原来的组件,只是在上面包裹一些东西。而有时会更改渲染逻辑,比如当wrappedcomponent资源没有加载回来时,页面显示loading,加载完成后才会显示,这就需要更改显示逻辑。反向继承HOC返回的React组件继承了被传入的组件,既然继承了被传入组件,是不是所有方法都可以使用呢?比如在render方法中渲染出之前的内容,可以直接使用super.render(),我们可以在render方法中重新写一个render,这样原有内容就都展示不出来了,想展示原有内容只需要调用super.render()即可。所以它能够访问到的区域、权限更多,相比属性代理方式,它更像打入组织内部,对其进行修改。

 

脑洞大开的HOC库——recompose

Recompose有很多很多实用的库,下面为大家介绍几个常见场景应用。

e1ead119a750b3d7712a0957470a79c138e729da

第一个情景是展示哪一个。有些时候,你需要根据后端返回值来做决策,例如展示Loading组件,之前你可能会将这部分判断写在render方法里,现在你可以将它们抽离出来了,将判断逻辑提前拿出来,我们的组件尽可能都是函数组件,不需要额外维护状态。顺带也可以将生命周期等方法挪出来,用高阶组件lifecycle代替。

如图所示,高阶组件是一层层被包裹起来的,最里面为wrappedcomponent组件,外部包裹一层branch高阶组件,branch专门用来做条件判断的,根据某一个值去判断真假,如果是真就会直接加载loading组件传递给你的业务组件,如果是假就会把另外一个高阶组件传递给你的业务组件,我们不需要在render方法里做这个判断。然后将代码发起请求的方式拿到lifecycle中去做,lifecycle本身可以写一些生命周期方法,state修改完后传递到branch高阶组件中透传,最终到达业务组件。

674a0d435f9487252ef1dfc97771b894db352637

第二个情景是维护组件自身的State。我们经常会有Tab切换,选择第一个、选择第二个等,将高亮的加上classname,点击展开(收起)等与业务数据无关的状态需要维护,回想以前的代码,我们可能会使用setState,但有时侯state和setstate不是很方便,组件可能非常长,也可能与真实业务代码融合在一起,容易使开发者混淆逻辑。有了recompose,我们可以使用withState和withHandlers来避免手动setState的出现,将展示逻辑和UI进行分离。

7649af3712a0e32015dbd24ec346544dfd690121

第三个情景是组件嵌套。在实际项目中,我们会有多个地方使用到Modal组件,如果都重复一遍上述代码,boilerplate代码将非常多,为此,我们可以将它转变为一个高阶组件,与常规方式不同,我们本次使用recompose提供的HOC来组织我们的代码。

 

DOM DIFF算法简析

b433a32607d8b1a89fa0a44e9155ad7d94e4d8d1

DOM DIFF是react应用中的精华所在,DOM DIFF在使用时有一些约定如下:

1.         DOM节点跨层级的移动操作特别少,可以忽略不计(例如A原本和B平级,随后A变成B的子节点)

2.         拥有相同类的两个组件将会生成相似的树形结构,拥有不同类的两个组件将会生成不同的树形结构(A和B组件结构不一致)

3.         同一层级的一组子节点,它们可以通过uuid进行区分。

DIFF算法在执行时有三个维度,分别是Tree DIFF、Component DIFF和Element DIFF,执行时按顺序依次执行,它们的差异仅仅因为DIFF粒度不同、执行先后顺序不同。

315badd9651f8d79363b01a506e8531759d40bfe

Tree DIFF是对树的每一层进行遍历,如果某组件不存在了,则会直接销毁。如图所示,左边是旧属,右边是新属,第一层是R组件,一模一样,不会发生变化;第二层进入Component DIFF,同一类型组件继续比较下去,发现A组件没有,所以直接删掉A、B、C组件;继续第三层,重新创建A、B、C组件。

5fbd248ebec60d443606aa8e612047d371355a40

如图所示,第一层遍历完,进行第二层遍历时,D和G组件是不同类型的组件,不同类型组件直接进行替换,将D删掉,再将G重建。

27222d09d321b46faeadca9a82dff6164cfbac12

Element DIFF紧接着以上统一类型组件继续比较下去,常见类型就是列表。同一个列表由旧变新有三种行为,插入、移动和删除,它的比较策略是对于每一个列表指定key,先将所有列表遍历一遍,确定要新增和删除的,再确定需要移动的。如图所示,第一步将D删掉,第二步增加E,再次执行时A和B只需要移动位置即可。

 

React Fiber

7d1162dd65baaa56bf26b21d3b4b9bdf52ecdbab

React Fiber是react执行渲染时的一种新的调度策略,JavaScript是单线程的,一旦组件开始更新,主线程就一直被React控制,这个时候如果再次执行交互操作,就会卡顿。

React Fiber重构这种方式,渲染过程采用切片的方式,每执行一会儿,就歇一会儿。如果有优先级更高的任务到来以后呢,就会先去执行,降低页面发生卡顿的可能性,使得React对动画等实时性要求较高的场景体验更好。

文章部分配图来自此文章:https://zhuanlan.zhihu.com/p/20346379

本文由云栖志愿小组毛鹤整理,编辑百见

版权声明:本文中所有内容均属于阿里云开发者社区所有,任何媒体、网站或个人未经阿里云开发者社区协议授权不得转载、链接、转贴或以其他方式复制发布/发表。申请授权请邮件developerteam@list.alibaba-inc.com,已获得阿里云开发者社区协议授权的媒体、网站,在转载使用时必须注明"稿件来源:阿里云开发者社区,原文作者姓名",违者本社区将依法追究责任。 如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件至:developer2020@service.aliyun.com 进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容。

分享:
人工智能
使用钉钉扫一扫加入圈子
+ 订阅

了解行业+人工智能最先进的技术和实践,参与行业+人工智能实践项目

其他文章