钩住在反应、预反应、反应ssr,中途中的实现原理

React的钩子是在纤程之后出现的特性,所以很多人误以为钩子一定是纤程实现的,其实不是。他们之间没有必然的联系。
现在钩子不仅在react中实现,在preact、react ssr、midway等框架中也有实现。它们的实现与光纤无关。
让我们来看看这些不同框架中的钩子是如何实现的:react是如何实现钩子的?
React通过jsx描述接口。会被babel或tsc等编译工具编译成渲染函数,然后执行生成vdom:
这里的渲染函数是React17之前的React.createElement:
在React 17之后,它被替换为jsx:
这个jsx-runtime将被自动引入,所以没有必要像以前一样为每个组件保留一个React导入。
render函数的执行生成vdom:
vdom的结构如下:
在React16之前,这个vdom将被递归地呈现,添加和删除真正的dom。
React16引入纤程架构后,又多了一步:首先将vdom转换成纤程,然后渲染纤程。
将vdom转换为纤程的过程称为reconcile,最后添加、删除和更改real dom的过程称为commit。
为什么要做这样的转换?
因为vdom只有子节点的引用,没有父节点和兄弟节点的引用,所以需要将所有vdom节点一次性递归渲染到dom中,不能中断。
如果被打断会怎么样?因为没有记录父节点和兄弟节点,所以只能继续处理子节点,而不能处理vdom的其他部分。
这也是React引入这种纤程结构的原因,即有父节点返回、子节点子节点、兄弟节点等的引用。可以中断,因为所有未处理的节点都可以在中断和恢复后找到。
纤维节点的结构如下:
这个过程是可以中断的,自然也是可以预定的,这就是schedule的过程。
因此,纤程架构分为三个阶段:调度、协调(vdom到纤程)和提交(更新到dom)。
可以在组件中使用钩子来访问一些值,这些值存储在纤程节点上。
例如,在该功能组件中使用了六个挂钩:
那么在相应的纤程节点上有一个6元素存储状态链表:
串行连接通过下一个:
memorizedState链表的不同元素上不同的钩子访问值,这就是react钩子的原理。
这个链表有一个创建阶段和一个更新阶段,所以你会发现useXxx的最终实现分为mountXxx和updateXxx:
这里的挂载阶段是创建挂钩节点并将它们组装到链表中:
将创建的钩子链表挂在纤程节点的memorizedState属性上。
当你更新的时候,你自然可以从纤程节点中取出这个钩子链表:
这样,useXxx的api就可以在多次渲染中找到纤维节点上对应的memorizedState。
这就是react hook的原理。可以看出,它将钩子存储在纤维节点中。
那么preact有什么区别呢?
preact如何实现钩子?
Preact是一个与react代码兼容的轻量级框架。它支持类组件和函数组件,还支持钩子等react特性。但是,它没有实现光纤架构。
因为它主要考虑的是体积的极端(只有3kb),而不是性能的极端。
刚才我们了解到,react在纤程节点上存储钩子链表。如果preact没有纤程节点,钩子链表会存在哪里?
其实很容易认为fiber只是修改了vdom提高了性能,和vdom没有本质区别,那为什么不直接把hook存储在vdom里呢?
事实上,preact只是将挂钩链表放在vdom上。
例如,这个功能组件有4个挂钩:
它的实现是访问vdom上相应的钩子:
它没有像react一样把hook分成挂载和更新两个阶段,而是把它们合并在一起。
如图所示,它在组件数组中存储钩子。_ _挂钩并通过下标访问它们。
该组件是vdom上的一个属性:

也就是说,钩子的值存储在vnode的数组中。_组件。_hooks。
比较react和preact之间实现钩子的区别:
在react中,挂钩链表存储在fiber node . memored state属性中,在preact中,挂钩链表存储在vnode中。_组件。_hooks属性。
react中的钩子链表由next串联,preact中的钩子链表是一个数组,用下标访问。
React将钩子链表的创建和更新分开,即useXxx分为mountXxx和updateXxx,合并在preact中。
所以钩子的实现并不依赖于纤程,它只是找一个地方存储钩子对应组件的数据,渲染时可以检索,存储在哪里并不重要。
因为vdom、纤程和组件渲染紧密相关,所以它们存储在这些结构中。
像react ssr实现钩子一样,它不存在于fiber或vdom上:
如何通过react ssr实现钩子
实际上,react-dom包既可以用作ssr,也可以用作csr:
当csr:
图像方法:

你觉得用ssr的时候会把vdom转换成光纤吗?
当然不是。纤程是一种引入的结构,用于提高在浏览器中运行时的渲染性能,使计算可中断,并在空闲时间进行计算。
服务器端渲染自然不需要光纤。
如果不需要纤程,那么它在哪里存储钩子链表?Vdom?
可以放在vdom里,但是没有。
比如useRef的钩子:
图片是以firstWorkInProgressHook开头,以next串联的链表。
所以,当react ssr时,钩子存在于全局变量上。
react csr和ssr在钩子实现原理上的区别;
Csr从vdom创建纤程,用于使渲染可中断,通过空闲调度提高性能,而ssr没有,vdom直接渲染。
在csr中,钩子被保存在纤程节点上,而在ssr中,它们被直接放在全局变量上,每个组件在处理后被清空。因为不会用两次。
Csr会把hook的创建和更新分为挂载和更新两个阶段,而ssr只能处理一次,只有创建阶段。
hooks的实现原理其实并不复杂,就是在一定的上下文中存储一个链表,然后hooks api从链表的不同元素中访问相应的数据,完成各自的逻辑。这个上下文可以是vdom、纤程甚至是全局变量。
然而,钩子的想法仍然很受欢迎。淘宝中途的服务器端框架引入了钩子的思想:
中途如何实现钩子
中途是Node.js框架:

服务器端自然没有vdom和fiber这样的结构,但是钩子的思想并不依赖于这些。要实现hooks的api,只需要把一个链表放在某个上下文中。
Midway实现了一个类似react钩子的api:
钩子链表存在于哪里的具体图片我没见过,但是我们掌握了钩子的实现原理,只要有一个上下文来存储钩子链表,就可以在任何地方。
摘要
React钩子是react纤程架构之后出现的一个特性。很多人误以为钩子必须配合光纤才能实现。我们已经分别考察了react、preact、react ssr和midway中钩子的实现,发现情况并非如此:
React就是把vdom转换成fiber,然后把钩子链表存储在fiber.memorizedState的属性中,通过next把它们串联起来。
Preact没有实现纤程,但是它把钩子链表放到了vnode上。_组件。_hooks属性,由数组实现,通过下标访问。
react ssr中不需要纤程,但是钩子链表不是挂在vdom上,而是直接放在一个全局变量上,因为只需要渲染一次,渲染完一个组件就可以清除全局变量。
Midway是Node.js框架,也实现了类似钩子的api。我们不知道具体放在哪里,但是只要有上下文来存储Hook链表就可以了。
那么,react钩子一定要靠光纤来实现吗?
显然,它可以与纤程、vdom、全局变量甚至任何上下文一起使用。将hooks api引入框架并不难。

其他教程

神曲相继问世,李荣浩、查理和莱各显神通。

2022-8-21 1:24:16

其他教程

那些让我们觉得「很酷」的声音有什么共同点?漫画为你揭秘。

2022-8-21 1:26:18

0 条回复 A文章作者 M管理员
    暂无讨论,说说你的看法吧
个人中心
购物车
优惠劵
今日签到
有新私信 私信列表
搜索