尧图网站建设 尧图网络
  • 首页
  • 关于我们
  • 服务项目
  • 案例展示
  • 建站流程
  • 资讯中心
  • 联系我们
首页/资讯中心/详情

react hook 原理

react hook 原理
📅 发布时间:2026/7/3 3:02:35

前言:

本篇文章为作者拜读外星人大佬文章所感受,旨在让更多的小白也能看懂理解,特来写文章分享感受,如有不对请多多指正(原文链接「react进阶」一文吃透react-hooks原理之前的两篇文章,分别介绍了react-hooks如何使用,以及自定义 - 掘金)

一、react fiber渲染机制

在了解reacthook之前,我们要先了解一下react fiber更新机制:

React fiber是react 16的渲染机制,他将react的组件树采用链表的方式进行切割,变为更细的fiber树,各个fiber之间支持任务的中断、恢复和优先级调度,防止浏览器渲染的时候阻塞一些更高优先级的点击输入等事件。

React fiber分为render和commit两个状态,rander状态用来计算需要更新的fiber树,计算diff差异,可以被中断,commit提交时来操作实际dom,不可被中断。

二、普通函数和组件函数

React 中的函数大致可以分为普通函数和组件函数。
普通函数就是普通的 JavaScript 函数,一般用于封装计算逻辑或工具方法,调用方式和 JS 函数一样,例如 sum(a, b)。
组件函数本质上也是 JavaScript 函数,但它会被 React 当成组件来渲染。函数组件通常首字母大写,返回 JSX 结构,使用时通过 这种标签形式。React 在第一次渲染函数组件时,会通过 renderWithHooks 执行组件函数,因此函数组件内部可以在顶层调用 useState、useEffect 等 Hook。

三、react Hook初始化流程

(1)renderWithHooks初始化环境

renderWithHooks会在组件函数被渲染的时候启用,它会初始化这个组件函数的如下参数:

1.current Fiber:当前组件内容树,在提交阶段会转化真正的dom树。初始为空

  1. workInProgress Fiber:本次要渲染的组件内容树。初始为当前组件初始组件内容树

  2. Component:组件本身

4.props:传进来的参数值

  1. context/secondArg: 传给组件的第二个参数,普通组件基本不用管

  2. renderLanes:组件组件渲染优先级

然后根据这个组件函数是否是第一次渲染,赋予ReactCurrentDispatcher.current不同的hooks。ReactCurrentDispatcher.current决定了hook的执行规则(也就是 useState、useEffect 等 Hook 最终会执行哪一套具体实现。)

对于第一次渲染组件,那么用的是HooksDispatcherOnMount hooks对象。 对于渲染后,需要更新的函数组件,则是HooksDispatcherOnUpdate对象,那么两个不同就是通过current树上是否memoizedState(hook信息)来判断的。如果current不存在,证明是第一次渲染函数组件。

(2)组件函数执行

调用Component(props, secondArg);执行我们的函数组件,我们的函数组件在这里真正的被执行了,此时,我们写的hooks也被依次执行。执行之后Components把hooks信息依次保存到workInProgress树上。最终函数返回jsx内容

(3)renderWithHooks清扫环境

ReactCurrentDispatcher.current置为ContextOnlyDispatcher ,此时渲染阶段结束,大部分hook函数再执行就会报错,防止回调函数等。最后再置空一些变量比如currentHook等等。

四、mountWorkInProgressHook挂载阶段创建工作树

初次渲染函数组件时启用,每次执行hook函数的时候都会创建一个hook对象,hook对象之间用链表串连在一起。最终mountWIPHook将链表返回,并将其挂载到WIP的memoizedState上。

Hook内的信息如下:

1.memoizedState:当前最新状态
2.baseState:当前优先级重播的起始位置,二者的值都由newState赋予
3.baseQueue:上一次被跳过的更新队列
4.queue:本次的更新队列
5.next:下一个hook地址

这么说大家也可能有点乱,我特意给大家梳理了一张图来便于理解

接下来我们来看看不同的hook函数在挂载阶段都有什么表现吧

(1)useState 状态如何变化

const [num,setNum] = useState(0)

useState在初始化的时候为mountState。首先mountState将初始化的state传给,经过mountWIPSHook初始化的hook里面的memoizedState和baseState,然后创建queue队列取保存更新信息。

useState的更新方法为dispatchAction,也就是我们的setNumber。dispatchAction的第一个和第二个参数已经被bind绑定为currentlyRenderingFiber和 queue。当调用setState的时候,dispatchAction会产生一个update对象来记录本次的修改信息,并把他放到hook的queue中。接下来判断react是否在渲染中,若在渲染中则标记,当前渲染结束后react会重新计算;不在渲染中则提前算出值并进行浅比较,结果相同则不更新,不同则进行更新。注意render是react来操作的,dispatchAction只是检测当前状态和通知react更新渲染。

(2)useEffect 变化之后,我们能做什么

useEffect(()=>{},[])

useEffect在初始化的时候也是mountEffect,接收create函数和deps依赖。mountEffect先用mountWIPHooks()的dispatch创建effect自己的hook对象,将create函数放到hook的memoizedState里面,并将该hook对象挂载到fiber树的memoizedState链表里面。接下来,mountEffect调用pushEffect方法,将useEffect创建一个effect对象,将其挂载到fiber树的updateQueue中。Effect对象中包含
1.tag 是否要重新执行create函数
2.create生成函数,是useEffect的第一个参数--回调函数
3.destroy销毁函数,也就是return里面的
4.deps依赖
5.next:下一个effect对象的位置

所以总体流程如下:

Mount阶段:函数组件先按照组件顺序初始化hook函数。 当外部触发更新事件的时候,react将useState等的hook变化存到queue里面

Render阶段:函数组件先按照顺序运行hook函数,若queue里面有更新变化则更新useState的值。当useState等hook函数执行完成,进入到更新effect阶段(因为effect的依赖项要在effect之前已经声明好)effect根据传入的deps和原来的deps进行浅比较,若变化则打上tag变化。

Commit 阶段:根据WIP fiber和current fiber进行对比,进行dom更新,更新结束后,将WIP fiber赋值给 current fiber

passive effect阶段:react扫描fiber里的updateQueue链表,对里面的tag进行判断进行重新执行

(3)useMemo 缓存计算值

useMemo在初始化采用mountMemo,mountMemo先初始化hooks,然后将函数计算的结果和依赖项以数组的形式存在hook的memoizedState中

(4)useRef 保存变量

useRef 在初始化执行mountRef,mountRef先初始化hook,然后将初始化的值存成一个对象{current:initalValue}(这样才能保证每次渲染拿到的值都有稳定的地址)。最后将这个对象存到hook的memoizedState中。

先写到这里(真的是太难啦,写作不易,多多指正)

相关新闻

  • AI Agent赋能外贸客户开发:从电梯行业实战看自动化精准获客
  • Z-Blog vs WordPress 多语言方案深度对比:中小站出海到底该选谁?
  • 从确定性代码到非确定性Agent:AI Agent工程的核心挑战与实战指南

最新新闻

  • Django分页封装
  • Selenium自动化测试与动态网页爬虫实战指南
  • ThinkPad风扇控制终极指南:TPFanCtrl2实现128级无级调速与智能温控
  • 近期零基础量化,工具重点要跟着阶段变
  • 组件类型-Props-Emits-Ref
  • CPPM注册职业采购经理怎么报名?报考条件、费用和证书查询一次说清

日新闻

  • JMeter接口测试实战:从核心元件到复杂场景构建
  • Java Applet版刽子手游戏源码:含完整项目结构、吊杆绘图与胜负逻辑
  • 使用Apache JMeter对RoadRunner PHP应用进行性能测试与调优指南

周新闻

  • Windows字体自定义终极方案:No!! MeiryoUI完全指南
  • Deepin Boot Maker:告别命令行,3分钟制作Linux启动盘的智能解决方案
  • Plain Craft Launcher 2:重新定义你的Minecraft游戏体验

月新闻

  • 2026年6月公司网站搭建最新热门渠道测评:四大低成本/零代码平台对比+避坑
  • 【Linux】Linux arm 编译QT程序,出现expected “}“报错
  • 【MATLAB例程】四基站二维AOA定位与距离辅助增强对比仿真。基于角度观测和测距修正的固定目标平面定位精度分析

关于尧图

  • 公司简介
  • 团队介绍
  • 企业文化
  • 荣誉资质

服务项目

  • 定制开发
  • 电商建站
  • UI 设计
  • 运维服务

快速链接

  • 案例展示
  • 建站流程
  • 常见问题
  • 资讯中心

联系方式

  • 📍北京市朝阳区互联网产业园 A 座 10 层
  • 📞400-888-8888
  • ✉️contact@rkmt.cn
  • 🕐周一至周日 9:00-21:00

© 2024 北京尧图网络科技有限公司 版权所有 | 京 ICP 备 XXXXXXXX 号