React Hooks 是什么,以及一些背后的原理

149 篇文章 0 订阅
149 篇文章 0 订阅

基本概念

React Hooks本质上是内置在React中的特殊函数,它可以允许我们连接到React的一些内部机制,换句话说,Hooks是一些公开内部响应功能的API,例如从Fiber tree中创建和访问状态变量,或者是在Fiber tree中记录一些副作用(side effects)。Fiber tree在React内部很深的地方,我们基本接触不到它,只有通过使用Hooks我们才能连接到这些内部机制。

值得一提

Hooks都以 use 开头,方便我们将其和普通函数区别开来,当我们自己去自定义一些需要的Hooks时请不要忘记也以 use 开头。说到自定义Hook,这可以说是Hooks最伟大的地方之一,它为开发人员提供了很简单的重用非可视化逻辑的方式。

曾经很长一段时间,如果我们想让组件的状态访问组件生命周期,我们不得不使用基于JavaScript的类组件,当然这引入了很多问题,所以React团队引入了Hooks。

React团队在旧文档中引入Hook的动机以及类组件的弊病 详情链接

现在拥有了Hooks,函数组件可以拥有自己的状态变量,甚至可以运行一些副作用,这是React迈出的一大步,也让它比以前更受欢迎。

Hooks的使用原则

  1. 只在顶层调用 Hooks

    • 不能在条件语句、循环、嵌套函数或者提前返回的情况下调用 Hooks。
    • 这是为了确保 Hooks 在每次渲染时都按照相同的顺序被调用,因为 Hooks 的行为依赖于它们的调用顺序。
  2. 只从 React 函数中调用 Hooks

    • 只能在函数组件或者自定义的 Hook 中调用 Hooks,而不能在普通函数或类组件中调用。

如果你安装了React-ES-Lint的话,这些规则会被默认执行,当你违反时是会报错的。

为什么Hooks依赖于调用顺序?

这就和我上一篇文章提到的内容有关了,当初次渲染完成时,React创建了一棵React Element Tree(React Virtual DOM),并且以此创建了一个Fiber tree,上面的每个元素都是一个Fiber,而在Fiber之中存储了很多的信息,包括props,DOM工作清单以及 组件实例中使用的所有Hooks的链表

光说无用,我来上个例子解释下。

假设我们的组件中有以下代码:

当然这段代码是错误的,因为有个条件调用,不信可以拿去运行下。我们先不管错误,假设这是可以运行的,那么目前的Hooks链表就应该长这样:

现在将A的数值更新成999,那么此时的条件调用就不起作用了,重渲染后State B就会因此消失,不再存在于这个链表之中。此时问题就来了,A的指向丢失,Effect Z也跟着,链表联系就被破坏了,那么React就无法正确追踪所有使用的Hook。

为什么Hooks会以一个这样奇怪的方式工作?

  1. Fiber tree并不会在每个重渲染之后重新创建,它的元素Fiber也是如此,所以 Hooks链表也不是重新创建 的,如果一个Hook从链表中消失,那么整个顺序就会被打破。
  2. 使用链表是将状态变量与其值关联的最简单的方法。从上面的例子来讲,我们可以简单的知道第一个state存储的值为666,第二个为空字符串...所以状态变量的值与调用顺序紧密相连,而且这也很方便,通过调用顺序,我们不必手动为每个状态变量命名(命名一多起来确实容易引发很多问题)

实践

讲了那么多不如亲自“触犯天条”来感受下Hooks到底是不是如此运作,大家且看我试~

我们在React开发工具中就可以发现,hooks里标注的确实是只有顺序和其值

接下来让我们来干一些违背祖宗之法的事!嘿嘿非常的刺激嗷

我们随手打开一个React项目,来添加一个条件调用,看看React会怎么报错。

很好,这个报错符合预期,不过还是无法运行,我们让eslint老实点,再看看当密码长度大于8时会报什么错。事情发展的越来越刺激了嗷

加一行注释eslint就老实了

程序如期运行,但是随着我们逐渐添加密码,当密码长度达到8时。。。

程序当场崩溃且报错,具体如下

Login.jsx:16 Warning: React has detected a change in the order of Hooks called by Login. This will lead to bugs and errors if not fixed. For more information, read the Rules of Hooks: https://reactjs.org/link/rules-of-hooks

   Previous render            Next render
   ------------------------------------------------------
1. useContext                 useContext
2. useContext                 useContext
3. useContext                 useContext
4. useContext                 useContext
5. useContext                 useContext
6. useContext                 useContext
7. useContext                 useContext
8. useContext                 useContext
9. useRef                     useRef
10. useContext                useContext
11. useLayoutEffect           useLayoutEffect
12. useCallback               useCallback
13. useState                  useState
14. useState                  useState
15. useEffect                 useState
   ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

结果非常的令人Amazing啊,在第15个顺序的Hook本该是Effect但是却变成了一个State,链表顺序从此位置断开,React无法再正确追踪Hook,只能委屈地向控制台打印错误。

原文链接:https://juejin.cn/post/7405388594829262884

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值