iis服务器助手广告广告
返回顶部
首页 > 资讯 > 前端开发 > JavaScript >ReactDOM隐藏特性详解
  • 907
分享到

ReactDOM隐藏特性详解

2024-04-02 19:04:59 907人浏览 安东尼
摘要

目录前言React DevTools 的原理渲染阶段FiberRoot/FibernodememoizedState 与 React Hooks实践:突破 useDebugValue

前言

有过 React 经验的开发者可能都使用过 React DevTools。

DevTools 提供了丰富的能力:展示组件树,组件的 props 与组件中 hook 的值。

React DevTools 是如何检测当前网页是否使用 React 以及是如何获取组件相关的众多数据呢?

React DevTools 的原理

打开 ReactDOM 代码时,用 devtools 为关键字搜索,你会发现许多与 React DevTools 相关的代码。

function injectInternals(internals) {
  if (typeof __REACT_DEVTOOLS_GLOBAL_HOOK__ === 'undefined') {
    // No DevTools
    return false;
  }
  var hook = __REACT_DEVTOOLS_GLOBAL_HOOK__;
  try {
    rendererID = hook.inject(internals); // We have successfully injected, so now it is safe to set up hooks.
    injectedHook = hook;
  } catch (err) {
    // ...
  } // DevTools exists
}

在浏览器控制台输入 __REACT_DEVTOOLS_GLOBAL_HOOK__ 详细看一下这个对象。

这个对象十分复杂,以下的几个方法倒是很值得关注。

onCommitFiberRoot

onCommitFiberUnmount

onPostCommitFiberRoot

渲染阶段

从名称来看,上面这几个方法与 ReactDOM 的渲染密切相关。

ReactDOM 在特定的阶段会调用这些的方法,比如:onCommitFiberRoot

function onCommitRoot(root, priorityLevel) {
  if (injectedHook && typeof injectedHook.onCommitFiberRoot === 'function') {
    try {
      // ...
      injectedHook.onCommitFiberRoot(rendererID, root, priorityLevel, didError);
    } catch (err) {}
  }
}

正是借助 __REACT_DEVTOOLS_GLOBAL_HOOK__,React DevTools 便与 ReactDOM 建立起了联系,从而拥有获取组件众多信息的能力。

FiberRoot/FiberNode

在新的 React 架构下,会先把 Virtual DOM 转成 FiberNode,然后再渲染 FiberNode。

onCommitFiberRoot 等方法中的传递的数据正是 FiberNode。

FiberNode 的结构是比较复杂的,可以简化为如下的结构:

interface ReactFiberRootNode {
  current: ReactFiberNode;
  // ...
}
interface ReactFiberNode {
  tag: number;
  stateNode: null | htmlElement; // dom 节点
  memoizedProps?: Record<string, any>; // props
  memoizedState: ClassComponentState | HookLinkedQueue | null; // hooks
  child?: ReactFiberNode;
  sibling?: ReactFiberNode;
  return: ReactFiberNode; // parent
  // ...
}

从上面的结构可以看出,FiberNode 包含了非常多与组件相关的信息。

stateNode 为组件对应真实的 DOM 节点,memoizedProps 为组件的 props

当组件为函数式组件时,tag 为 0,memoizedState 保存了组件中的 hooks 信息。

当组件为类组件时,tag 为 1,memoizedState 则是组件的 state

如下图所示,FiberNode 节点形成一个链表结构。

只要能找到组件对应的 FiberNode,我们便可以做到在运行期间以无侵入的方法获取组件的众多信息。比如:通过 FiberNode 进行遍历,实现 findNativeNodesForFiber 方法,用以查找其对应的真实 DOM 节点。

function findNativeNodesForFiber(node?: ReactFiberNode) {
  // ...
  // 先遍历 child
  const { child } = node;
  collectStateNode();
  // 再遍历所有的 sibling
  let current = child?.sibling;
  while (current) {
    collectStateNode();
    current = current.sibling;
  }
  // ...
}

React DevTools 中审查元素功能正是基于类似的原理去实现。

memoizedState 与 React Hooks

上文中提到当组件为函数式组件时,memoizedState 保存了 React Hooks 相关的信息。与 FiberNode 类似,React Hooks 也形成一个链表。

export interface HookLinkedQueue {
  memoizedState: any; // 渲染时的值
  next: HookLinkedQueue | null;
  // ...
}

React Hook 将其数据都保存在 memoizedState 上。比如对于 useRef 来说,ref.current 值就是 memoizedState。类似的,可以实现 inspectSomeHooksOfFiber 来获取组件内使用特定 hook 中保存的值。

function inspectRefHooksOfFiber(node: ReactFiberNode) {
  let current: HookLinkedQueue | null = node.memoizedState;
  while (current) {
    retrieveValue(current);
    current = current.next;
  }
}

实践:突破 useDebugValue 的限制

useDebugValue 是 React 内置的一个 hook,用以在 React DevTools 中显示自定义 hook 的标签。它的限制是只能在 hook 中使用。借助前文介绍的知识点,我们可以实现一个增加版的 useDebugValue,你可以像普通的 hook 一样来使用它,没有其他限制。

useDebugValueAnywhere 的实现

useDebugValueAnywhere 实现比较简单,name 表明数据的名称,用一个特殊的 ref 对象来存储 debug 相关的数据。

export function useDebugValueAnywhere(name: string, data: any) {
  const ref = useRef({
    [DebugHookKey]: {
      name,
      data,
    },
  });
  // ...
}

特定的 devtools

参考 React DevTools 的逻辑,在 __REACT_DEVTOOLS_GLOBAL_HOOK__ 中注入我们的 onCommitFiberRoot 方法,从而确保 ReactDOM 每次渲染时,能获取最新的 FiberNode。

currentHook.onCommitFiberRoot = function (...args) {
  handleCommitFiberRoot(...args); // 注入
  oldOnCommitFiberRoot.apply(this, args);
};

接下来便是对 FiberNode 进行遍历。在遍历的过程中,检查每个 FiberNode 中 memoizedState 链表,检测组件的 hooks 中是否用到了 useDebugValueAnywhere

如果存在,就将值 FiberNode 与 hook 中的值保存起来。

{
  visitFiberNode(node?: ReactFiberNode) {
    if (!node) return;
    this.inspectFiber(node);
    this.visitFiberNode(node.child);
    let { sibling } = node;
    while (sibling) {
      this.visitFiberNode(sibling);
      sibling = sibling.sibling;
    }
  }
}

剩下的工作就是考虑以何种形式去展示收集到的 debug 信息。在 PC 端可以直接输出数据到控制台;在移动端 vConsole 使用较多,那么就可以基于 vConsole 开发一个插件,实现一个极简版的 React DevTools,专门用以展示这些信息。

完整的代码。

总结

本文剖析了 React DevTools 的原理,介绍隐藏在 ReactDOM 中的一些特性,并带领大家熟悉了一下 React Fiber 架构。基于上述原理,可以开发一个增加版的 useDebugValue

由于本文介绍的特性并非公开的 api,没有兼容性。当 React/ReactDOM 版本升级时,还需要再做适配,因此只适合用来开发 DevTools 之类的工具,不推荐业务开发使用。

以上就是ReactDOM 隐藏特性详解的详细内容,更多关于ReactDOM 隐藏特性的资料请关注编程网其它相关文章!

--结束END--

本文标题: ReactDOM隐藏特性详解

本文链接: https://www.lsjlt.com/news/166599.html(转载时请注明来源链接)

有问题或投稿请发送至: 邮箱/279061341@qq.com    QQ/279061341

本篇文章演示代码以及资料文档资料下载

下载Word文档到电脑,方便收藏和打印~

下载Word文档
猜你喜欢
  • ReactDOM隐藏特性详解
    目录前言React DevTools 的原理渲染阶段FiberRoot/FiberNodememoizedState 与 React Hooks实践:突破 useDebugValue...
    99+
    2024-04-02
  • Python有哪些隐藏特性
    这篇文章主要讲解了“Python有哪些隐藏特性”,文中的讲解内容简单清晰,易于学习与理解,下面请大家跟着小编的思路慢慢深入,一起来研究和学习“Python有哪些隐藏特性”吧!案例一:案例二:案例三:很好理解, 对吧 说明:这些行为是由于 C...
    99+
    2023-06-02
  • Python隐藏的特性有哪些
    本篇内容主要讲解“Python隐藏的特性有哪些”,感兴趣的朋友不妨来看看。本文介绍的方法操作简单快捷,实用性强。下面就让小编来带大家学习“Python隐藏的特性有哪些”吧!1...是的,你没看错,在Python中...是一个有效的构造。.....
    99+
    2023-06-15
  • CSS3中的隐藏特性有哪些
    这篇文章主要介绍“CSS3中的隐藏特性有哪些”的相关知识,小编通过实际案例向大家展示操作过程,操作方法简单快捷,实用性强,希望这篇“CSS3中的隐藏特性有哪些”文章能帮助大家解决问题。 CSS3为web设...
    99+
    2024-04-02
  • python学习字符串驻留与常量折叠隐藏特性详解
    下面是Python字符串的一些微妙的特性,绝对会让你大吃一惊。 案例一: 案例二: 案例三: 很好理解, 对吧? 说明: 这些行为是由于 Cpython 在编译优化时,...
    99+
    2024-04-02
  • win10隐藏特定格式文件如何隐藏
    本篇内容介绍了“win10隐藏特定格式文件如何隐藏”的有关知识,在实际案例的操作过程中,不少人都会遇到这样的困境,接下来就让小编带领大家学习一下如何处理这些情况吧!希望大家仔细阅读,能够学有所成!在需要隐藏文件的文件夹中新建文本文档,如果要...
    99+
    2023-07-01
  • JavaScript Jest 挖掘宝藏:发现隐藏的特性和技巧
    二、 Jet 可以轻松地连接到各种类型的数据库,如 MySQL、PostgreSQL、MongoDB、Cassandra、Redis、DynamoDB 等。一旦连接,您可以可视化和浏览数据库中的表、行和列,让您全面直观地查看数据。 三、 ...
    99+
    2024-02-17
    GUI 数据库管理 敏捷开发
  • C++中的覆盖和隐藏详解
    目录1. 前言2. 共性3. 区别4. 区分5.参考文章总结1. 前言 继承是面向对象编程的重要特性,在c++中,当父类与子类出现同名函数时,会出现两种情况:覆写和隐藏,本文主要讨论...
    99+
    2024-04-02
  • 详解JavaScript的Symbol类型、隐藏属性、全局注册表
    目录Symbol类型的使用Symbol简介Symbol类型的描述Symbol不会隐式转字符串Symbol类似作为对象的属性键创建Symbol键for…in中被跳过隐藏自...
    99+
    2024-04-02
  • TP3隐藏index.php设置步骤详解
    TP3是一个PHP框架,帮助开发者快速构建Web应用程序。其默认情况下,URL链接中会包含index.php作为默认入口文件,但有时候我们希望隐藏index.php,使得URL更加美观...
    99+
    2024-04-02
  • dedecms隐藏栏目的设置方法详解
    《DedeCMS隐藏栏目的设置方法详解,需要具体代码示例》 在使用DedeCMS建站过程中,有时候我们需要对一些栏目进行隐藏,不在站点前台展示。本文将详细介绍DedeCMS隐藏栏目的设...
    99+
    2024-03-15
    dedecms 设置方法 隐藏栏目
  • ASP 性能调优秘籍:解锁隐藏速度
    网站性能对于用户体验和搜索引擎排名至关重要。ASP 作为一种动态 Web 技术,可以通过适当的调优措施显着提升其响应速度。以下秘籍将指导您解锁 ASP 网站的隐藏速度潜力: 1. 使用缓存 缓存是存储经常请求的数据的临时存储机制。通过缓...
    99+
    2024-03-08
    ASP、性能调优、缓存、优化、代码审查
  • html中隐藏属性是哪个
    这篇文章主要介绍了html中隐藏属性是哪个,具有一定借鉴价值,感兴趣的朋友可以参考下,希望大家阅读完这篇文章之后大有收获,下面让小编带着大家一起了解一下。html隐藏属性是hidden,该属性是布尔属性;hidden属性可用于防止用户查看元...
    99+
    2023-06-14
  • 详解QTreeWidget隐藏节点的两种方式
    目录简述方法一:直接隐藏式方法二:间接隐藏式结尾简述 关于QTreeWidget隐藏节点有两种方式,一种是直接隐藏,一种是间接隐藏,但是两种方式各有差异,下面请听具体解说。 方法一:...
    99+
    2024-04-02
  • JDK10新特性详解
    1、局部变量var      将前端思想var关键字引入java后段,自动检测所属于类型,一种情况除外,不能为null,因为不能判断具体类型,会报异常。@Testpublic void te...
    99+
    2023-06-02
  • Tapestry5新特性详解
    Tapestry5是一个轻量级的、开源的Java Web框架,它提供了一种简化Web开发的方式。下面是Tapestry5的一些新特性...
    99+
    2023-09-22
    Tapestry
  • Java8新特性详解
    陈老老老板 说明:新的专栏,本专栏专门讲Java8新特性,把平时遇到的问题与Java8的写法进行总结,需要注意的地方都标红了,一起加油。 本文是介绍Java8新特性与常用方法(此篇只做大体介绍了解,之后会把重...
    99+
    2023-08-17
    java jvm android
  • JDK11新特性详解
    1、增强局部变量类型推断varConsumer<String> consumer = t -> System.out.println(t.toUpperCase());Co...
    99+
    2023-06-02
  • JDK9新特性详解
    1、Java9新特性之目录结构      包含jdk8及以前的jdk版本,所有目录结构以及目录含义如图:        jdk9之后,目录结...
    99+
    2023-06-02
  • 深入了解PHP参数隐藏的重要性
    PHP参数隐藏是构建安全可靠的网站和应用程序的关键一环。通过隐藏参数,可以保护敏感信息不被恶意用户窃取,提高系统的安全性和稳定性。在本文中,我们将深入探讨PHP参数隐藏的重要性,并结合...
    99+
    2024-03-09
    隐私保护 php参数隐藏 参数安全性
软考高级职称资格查询
编程网,编程工程师的家园,是目前国内优秀的开源技术社区之一,形成了由开源软件库、代码分享、资讯、协作翻译、讨论区和博客等几大频道内容,为IT开发者提供了一个发现、使用、并交流开源技术的平台。
  • 官方手机版

  • 微信公众号

  • 商务合作