目录
react 如何实现 hooks
preact 如何实现 hooks
react ssr 如何实现 hooks
midway 如何实现 hooks
总结
首页 web前端 js教程 react如何实现hooks?必须依赖 Fiber 么?

react如何实现hooks?必须依赖 Fiber 么?

Apr 20, 2022 pm 08:52 PM
react

react如何实现hooks?React Hooks 的实现必须依赖 Fiber 么?下面本篇文章带大家来看看不同框架中的 hooks 都是怎么实现的,希望对大家有所帮助!

react如何实现hooks?必须依赖 Fiber 么?

React 的 hooks 是在 fiber 之后出现的特性,所以很多人误以为 hooks 是必须依赖 fiber 才能实现的,其实并不是,它们俩没啥必然联系。【相关推荐:Redis视频教程

现在,不止 react 中实现了 hooks,在 preact、react ssr、midway 等框架中也实现了这个特性,它们的实现就是不依赖 fiber 的。

我们分别来看一下这些不同框架中的 hooks 都是怎么实现的:

react 如何实现 hooks

react 是通过 jsx 描述界面的,它会被 babel 或 tsc 等编译工具编译成 render function,然后执行产生 vdom:

1.png

这里的 render function 在 React17 之前是 React.createElement:

2.png

在 React 17 之后换成了 jsx:

3.png

这个 jsx-runtime 会自动引入,不用像之前那样每个组件都要保留一个 React 的 import 才行。

render function 执行产生 vdom:

4.png

vdom 的结构是这样的:

5.png

在 React16 之前,会递归渲染这个 vdom,增删改真实 dom。

6.png

而在 React16 引入了 fiber 架构之后就多了一步:首先把 vdom 转成 fiber,之后再渲染 fiber。

7.png

vdom 转 fiber 的过程叫做 reconcile,最后增删改真实 dom 的过程叫做 commit。

为什么要做这样的转换呢?

因为 vdom 只有子节点 children 的引用,没有父节点 parent 和其他兄弟节点 sibling 的引用,这导致了要一次性递归把所有 vdom 节点渲染到 dom 才行,不可打断。

万一打断了会怎么样呢?因为没有记录父节点和兄弟节点,那只能继续处理子节点,却不能处理 vdom 的其他部分了。

所以 React 才引入了这种 fiber 的结构,也就是有父节点 return、子节点 child、兄弟节点 sibling 等引用,可以打断,因为断了再恢复也能找到后面所有没处理过的节点。

fiber 节点的结构是这样的:

8.png

这个过程可以打断,自然也就可以调度,也就是 schdule 的过程。

所以 fiber 架构就分为了 schdule、reconcile(vdom 转 fiber)、commit(更新到 dom)三个阶段。

函数组件内可以用 hooks 来存取一些值,这些值就是存在 fiber 节点上的。

比如这个函数组件内用到了 6 个 hook:

9.png

那么对应的 fiber 节点上就有个 6 个元素的 memorizedState 链表:

10.png

通过 next 串联起来:

11.png

不同的 hook 在 memorizedState 链表不同的元素上存取值,这就是 react hooks 的原理。

这个链表有创建阶段和更新阶段,所以你会发现 useXxx 的最终实现都分为了 mountXxx 和 updateXxx:

12.png

这里的 mount 阶段就是创建 hook 节点并组装成链表的:

13.png

会把创建好的 hook 链表挂到 fiber 节点的 memorizedState 属性上。

那更新的时候自然也就能从 fiber 节点上取出这个 hook 链表:

14.png

这样在多次渲染中,useXxx 的 api 都能在 fiber 节点上找到对应的 memorizedState。

这就是 react hooks 的原理,可以看到它是把 hook 存在 fiber 节点上的。

那 preact 有什么不同呢?

preact 如何实现 hooks

preact 是兼容 react 代码的更轻量级的框架,它支持 class 组件和 function 组件,也支持了 hooks 等 react 特性。不过它没有实现 fiber 架构。

因为它主要考虑的是体积的极致(只有 3kb),而不是性能的极致。

15.png

刚才我们了解了 react 是把 hook 链表存放在 fiber 节点上的,那 preact 没有 fiber 节点,会把 hook 链表存在哪呢?

其实也很容易想到,fiber 只是对 vdom 做了下改造用于提升性能的,和 vdom 没啥本质的区别,那就把 hook 存在 vdom 上不就行了?

确实,preact 就是把 hook 链表放在了 vdom 上。

比如这个有 4 个 hooks 的函数组件:

16.png

它的实现就是在 vdom 上存取对应的 hook:

17.png

18.png

它没有像 react 那样把 hook 分为 mount 和 update 两个阶段,而是合并到一起处理了。

如图,它把 hooks 存在了 component.__hooks 的数组上,通过下标访问。

这个 component 就是 vdom 上的一个属性:

19.png

也就是把 hooks 的值存在了 vnode._component._hooks 的数组上。

对比下 react 和 preact 实现 hooks 的差异:

  • react 中是把 hook 链表存放在 fiberNode.memorizedState 属性上,preact 中是把 hook 链表存放在 vnode._component._hooks 属性上

  • react 中的 hook 链表通过 next 串联,preact 中的 hook 链表就是个数组,通过下标访问

  • react 把 hook 链表的创建和更新分离开,也就是 useXxx 会分为 mountXxx 和 updateXxx 来实现,而 preact 中合并在一起处理的

所以说,hooks 的实现并不依赖 fiber,它只不过是找个地方存放组件对应的 hook 的数据,渲染时能取到就行,存放在哪里是无所谓的。

因为 vdom、fiber 和组件渲染强相关,所以存放在了这些结构上。

像 react ssr 实现 hooks,就既没有存在 fiber 上,也没有存在 vdom 上:

react ssr 如何实现 hooks

其实 react-dom 包除了可以做 csr 外,也可以做 ssr:

csr 时使用 react-dom 的 render 方法:

20.png

ssr 的时候使用 react-dom/server 的 renderToString 方法或 renderToStream 方法:

21.png

大家觉得 ssr 的时候会做 vdom 到 fiber 的转换么?

肯定不会呀,fiber 是为了提高在浏览器中运行时的渲染性能,把计算变成可打断的,在空闲时做计算,才引入的一种结构。

服务端渲染自然就不需要 fiber。

不需要 fiber 的话,它把 hook 链表存放在哪里呢?vdom 么?

确实可以放在 vdom,但是其实并没有。

比如 useRef 这个 hooks:

22.png

它是从 firstWorkInProgressHook 开始的用 next 串联的一个链表。

23.png

而 firstWorkInProgressHook 最开始用 createHook 创建的第一个 hook 节点:

24.png

并没有挂载到 vdom 上。

为什么呢?

因为 ssr 只需要渲染一次呀,又不需要更新,自然没必要挂到 vdom 上。

只要每次处理完每个组件的 hooks 就清空一下这个 hook 链表就行:

25.png

26.png

27.png

所以,react ssr 时,hooks 是存在全局变量上的。

对比下 react csr 和 ssr 时的 hooks 实现原理的区别:

  • csr 时会从 vdom 创建 fiber,用于把渲染变成可打断的,通过空闲调度来提高性能,而 ssr 时不会,是 vdom 直接渲染的

  • csr 时把 hooks 保存到了 fiber 节点上,ssr 时是直接放在了全局变量上,每个组件处理完就清空。因为不会用第二次了

  • csr 时会把 hook 的创建和更新分为 mount 和 update 两个阶段,而 ssr 因为只会处理一次,只有创建阶段

hooks 的实现原理其实不复杂,就是在某个上下文中存放一个链表,然后 hooks api 从链表不同的元素上访问对应的数据来完成各自的逻辑。这个上下文可以是 vdom、fiber 甚至是全局变量。

不过 hooks 这个思想还是挺火的,淘宝出的服务端框架 midway 就在引入了 hooks 的思想:

midway 如何实现 hooks

midway 是一个 Node.js 框架:

28.png

服务端框架自然就没有 vdom、fiber 这种结构,不过 hooks 的思想并不依赖这些,实现 hooks 的 api 只需要在某个上下文放一个链表就行。

midway 就实现了类似 react hooks 的 api:

29.png

30.png

具体它这个 hook 链表存在哪我还没看,不过我们已经掌握 hooks 的实现原理了,只要有个上下文存放 hook 链表就行,在哪都可以。

总结

react hooks 是在 react fiber 架构之后出现的特性,很多人误以为 hooks 必须配合 fiber 才能实现,我们分别看了 react、preact、react ssr、midway 中的 hooks 的实现,发现并不是这样的:

  • react 是把 vdom 转成 fiber,然后把 hook 链表存放到了 fiber.memorizedState 属性上,通过 next 串联
  • preact 没有实现 fiber,它是把 hook 链表放到了 vnode._component._hooks 属性上,数组实现的,通过下标访问
  • react ssr 时不需要 fiber,但是也没有把 hook 链表挂到 vdom 上,而是直接放在了一个全局变量上,因为只需要渲染一次,渲染完一个组件就清空这个全局变量就行
  • midway 是一个 Node.js 框架,它也实现了 hooks 类似的 api,具体放在哪我们没深入,但是只要有个上下文存放 hook 链表就行

所以,react hooks 必须依赖 fiber 才能实现么?

明显不是,搭配 fiber、搭配 vdom、搭配全局变量,甚至任何一个上下文都可以。

更多编程相关知识,请访问:编程视频!!

以上是react如何实现hooks?必须依赖 Fiber 么?的详细内容。更多信息请关注PHP中文网其他相关文章!

本站声明
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系admin@php.cn

热AI工具

Undresser.AI Undress

Undresser.AI Undress

人工智能驱动的应用程序,用于创建逼真的裸体照片

AI Clothes Remover

AI Clothes Remover

用于从照片中去除衣服的在线人工智能工具。

Undress AI Tool

Undress AI Tool

免费脱衣服图片

Clothoff.io

Clothoff.io

AI脱衣机

Video Face Swap

Video Face Swap

使用我们完全免费的人工智能换脸工具轻松在任何视频中换脸!

热工具

记事本++7.3.1

记事本++7.3.1

好用且免费的代码编辑器

SublimeText3汉化版

SublimeText3汉化版

中文版,非常好用

禅工作室 13.0.1

禅工作室 13.0.1

功能强大的PHP集成开发环境

Dreamweaver CS6

Dreamweaver CS6

视觉化网页开发工具

SublimeText3 Mac版

SublimeText3 Mac版

神级代码编辑软件(SublimeText3)

如何利用React和WebSocket构建实时聊天应用 如何利用React和WebSocket构建实时聊天应用 Sep 26, 2023 pm 07:46 PM

如何利用React和WebSocket构建实时聊天应用引言:随着互联网的快速发展,实时通讯越来越受到人们的关注。实时聊天应用已经成为现代社交和工作生活中不可或缺的一部分。本文将介绍如何利用React和WebSocket构建一个简单的实时聊天应用,并提供具体的代码示例。一、技术准备在开始构建实时聊天应用之前,我们需要准备以下技术和工具:React:一个用于构建

React前后端分离指南:如何实现前后端的解耦和独立部署 React前后端分离指南:如何实现前后端的解耦和独立部署 Sep 28, 2023 am 10:48 AM

React前后端分离指南:如何实现前后端的解耦和独立部署,需要具体代码示例在当今的Web开发环境中,前后端分离已经成为一种趋势。通过将前端和后端代码分开,可以使得开发工作更加灵活、高效,并且方便进行团队协作。本文将介绍如何使用React实现前后端分离,从而实现解耦和独立部署的目标。首先,我们需要理解什么是前后端分离。传统的Web开发模式中,前端和后端是耦合在

如何利用React和Flask构建简单易用的网络应用 如何利用React和Flask构建简单易用的网络应用 Sep 27, 2023 am 11:09 AM

如何利用React和Flask构建简单易用的网络应用引言:随着互联网的发展,网络应用的需求也越来越多样化和复杂化。为了满足用户对于易用性和性能的要求,使用现代化的技术栈来构建网络应用变得越来越重要。React和Flask是两种在前端和后端开发中非常受欢迎的框架,它们可以很好的结合在一起,用来构建简单易用的网络应用。本文将详细介绍如何利用React和Flask

如何利用React和RabbitMQ构建可靠的消息传递应用 如何利用React和RabbitMQ构建可靠的消息传递应用 Sep 28, 2023 pm 08:24 PM

如何利用React和RabbitMQ构建可靠的消息传递应用引言:现代化的应用程序需要支持可靠的消息传递,以实现实时更新和数据同步等功能。React是一种流行的JavaScript库,用于构建用户界面,而RabbitMQ是一种可靠的消息传递中间件。本文将介绍如何结合React和RabbitMQ构建可靠的消息传递应用,并提供具体的代码示例。RabbitMQ概述:

React代码调试指南:如何快速定位和解决前端bug React代码调试指南:如何快速定位和解决前端bug Sep 26, 2023 pm 02:25 PM

React代码调试指南:如何快速定位和解决前端bug引言:在开发React应用程序时,经常会遇到各种各样的bug,这些bug可能使应用程序崩溃或导致不正确的行为。因此,掌握调试技巧是每个React开发者必备的能力。本文将介绍一些定位和解决前端bug的实用技巧,并提供具体的代码示例,帮助读者快速定位和解决React应用程序中的bug。一、调试工具的选择:在Re

React Router使用指南:如何实现前端路由控制 React Router使用指南:如何实现前端路由控制 Sep 29, 2023 pm 05:45 PM

ReactRouter使用指南:如何实现前端路由控制随着单页应用的流行,前端路由成为了一个不可忽视的重要部分。ReactRouter作为React生态系统中最受欢迎的路由库,提供了丰富的功能和易用的API,使得前端路由的实现变得非常简单和灵活。本文将介绍ReactRouter的使用方法,并提供一些具体的代码示例。安装ReactRouter首先,我们需

如何利用React和Google BigQuery构建快速的数据分析应用 如何利用React和Google BigQuery构建快速的数据分析应用 Sep 26, 2023 pm 06:12 PM

如何利用React和GoogleBigQuery构建快速的数据分析应用引言:在当今信息爆炸的时代,数据分析已经成为了各个行业中不可或缺的环节。而其中,构建快速、高效的数据分析应用则成为了许多企业和个人追求的目标。本文将介绍如何利用React和GoogleBigQuery结合起来构建快速的数据分析应用,并提供详细的代码示例。一、概述React是一个用于构建

如何利用React和Apache Kafka构建实时数据处理应用 如何利用React和Apache Kafka构建实时数据处理应用 Sep 27, 2023 pm 02:25 PM

如何利用React和ApacheKafka构建实时数据处理应用引言:随着大数据与实时数据处理的兴起,构建实时数据处理应用成为了很多开发者的追求。React作为一个流行的前端框架,与ApacheKafka作为一个高性能的分布式消息传递系统的结合,可以帮助我们搭建实时数据处理应用。本文将介绍如何利用React和ApacheKafka构建实时数据处理应用,并

See all articles