• react源码中的hooks


    今天,让我们一起深入探究 React Hook 的实现方法,以便更好的理解它。但是,它的各种神奇特性的不足是,一旦出现问题,调试非常困难,这是由于它的背后是由复杂的堆栈追踪(stack trace)支持的。因此,通过深入学习 React 的新特性:hook 系统,我们就能比较快地解决遇到的问题,甚至可以直接杜绝问题的发生。

    在开始讲解之前,我先声明我不是 React 的开发者或者维护者,所以我的理解可能也并不是完全正确。我确实非常深入地研究过了 React 的 hook 系统的实现,但是无论如何我仍无法保证这就是 React 实际的工作方式。话虽如此,我还是会用 React 源代码中的证据和引用来支持我的文章,使我的论点尽可能坚实。

    React hook 系统概要示意图


    我们先来了解 hook 的运行机制,并要确保它一定在 React 的作用域内使用,因为如果 hook 不在正确的上下文中被调用,它就是毫无意义的,这一点你或许已经知道了。

    Dispatcher

    dispatcher 是一个包含了 hook 函数的共享对象。基于 ReactDOM 的渲染状态,它将会被动态的分配或者清理,并且它能够确保用户不可在 React 组件之外获取 hook(详见源码)。

    在切换到正确的 Dispatcher 以渲染根组件之前,我们通过一个名为 enableHooks 的标志来启用/禁用 hook。在技术上来说,这就意味着我们可以在运行时开启或关闭 hook。React 16.6.X 版本中也有对此的实验性实现,但它实际上处于禁用状态(详见源码)

    当我们完成渲染工作后,我们将 dispatcher 置空并禁止用户在 ReactDOM 的渲染周期之外使用 hook。这个机制能够保证用户不会做什么蠢事(详见源码)。

    dispatcher 在每次 hook 的调用中都会被函数 resolveDispatcher() 解析。正如我之前所说,在 React 的渲染周期之外,这些都无意义了,React 将会打印出警告信息:“hook 只能在函数组件内部调用”(详见源码)。

    let currentDispatcher
    const dispatcherWithoutHooks = {
        /* ... */ }
    const dispatcherWithHooks = {
        /* ... */ }
    
    function resolveDispatcher() {
       
      if (currentDispatcher) return currentDispatcher  throw Error("Hooks can't be called")}function useXXX(...args) {
       
      const dispatcher = resolveDispatcher()
      return dispatcher.useXXX(...args)
    }
    
    function renderRoot() {
       
      currentDispatcher = enableHooks ? dispatcherWithHooks : dispatcherWithoutHooks  performWork()  currentDispatcher = null
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18

    dispatcher 实现方式概览。

    现在我们简单了解了 dispatcher 的封装机制,下面继续回到本文的核心 —— hook。下面我想先给你介绍一个新的概念:

    hook 队列

    在 React 后台,hook 被表示为以调用顺序连接起来的节点。这样做原因是 hook 并不能简单的被创建然后丢弃。它们有一套特有的机制,也正是这些机制让它们成为 hook。一个 hook 会有数个属性,在继续学习之前,我希望你能牢记于心:

    • 它的初始状态会在初次渲染的时候被创建。
    • 它的状态可以在运行时更新。
    • React 可以在后续渲染中记住 hook 的状态。
    • React 能根据调用顺序提供给你正确的状态。
    • React 知道当前 hook 属于哪个 fiber。

    另外,我们也需要重新思考看待组件状态的方式。目前,我们只把它看作一个简单的对象:

    {
       
      foo: 'foo',
      bar: 'bar',
      baz: 'baz',
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    旧视角理解 React 的状态

    但是当处理 hook 的时候,状态需要被看作是一个队列,每个节点都表示一个状态模型:

    相关参考视频讲解:进入学习

    {
       
      memoizedState: 'foo',
      next: {
       
        
    • 1
    • 2
    • 3
    • 4
    • 5
  • 相关阅读:
    时隔六年,FreeDOS终于更新,是否还能与Windows一战?
    第四章 文件管理 三、文件目录
    【LeetCode】332. 重新安排行程
    Chrome、Edge 合力“围剿“,Safari 夹缝求生?
    【Linux网络编程】Socket-TCP实例
    2010-2021年北大中国商业银行数字化转型指数数据(第三期)
    Redis分布式锁实现Redisson 15问
    【T+】畅捷通T+增加会计科目提示执行超时已过期。
    比较两个对象 取最大值 并返回对象
    68、Spring Data JPA 的 方法名关键字查询(全自动,既不需要提供sql语句,也不需要提供方法体)
  • 原文地址:https://blog.csdn.net/weixin_59558923/article/details/127745405