likes
comments
collection
share

利用click-to-component查看React Fiber结构,通透直观,浅显易懂!

作者站长头像
站长
· 阅读数 37

最近在研究click-to-component这个小工具的时候,偶然发现它与React Fiber有紧密的联系,可以利用它查看任意DOM节点所对应的FiberNode,这可比网上铺天盖地的文章直观多了!

click-to-component是什么?

大家在接手一个不太熟悉的大项目时,想找到对应元素的代码是挺费劲的,又是动态路由又是公共组件啥的,我就想知道描述这个DOM元素的JSX片段在哪,别让我去文件夹里面找了!click-to-component就是解决这个问题的,可以让你选择DOM元素后直接跳转到相关代码位置。

利用click-to-component查看React Fiber结构,通透直观,浅显易懂!

umi内置了这个工具,可以直接修改配置开启

利用click-to-component查看React Fiber结构,通透直观,浅显易懂!

click-to-component的原理

先把它clone下来看一下 github.com/ericclemmon…

利用click-to-component查看React Fiber结构,通透直观,浅显易懂! 是一个用到了pnpm workspace的monorepo,apps里面准备了三个demo项目,packages里的click-to-react-component就是它本身,我们直接pnpm install然后启动apps里的Next.js项目。

cd apps/next
pnpm dev

启动后不一定可以正常跳转,是因为这个NEXT_PUBLIC_CTC_EDITOR是vscode-insiders?大部分人应该都是vscode稳定版本,我们改成vscode就行了。 利用click-to-component查看React Fiber结构,通透直观,浅显易懂!

然后就是一顿调试,找到了ClickToComponent.js下的这段代码。

利用click-to-component查看React Fiber结构,通透直观,浅显易懂! 原来就是用某种手段得到了一个file协议的url,然后用location.assign就能跳转到对应位置,editor就是我们刚改的vscode,关键是看下path怎么取到的。

经过几个getXXX函数之后,最终找到了getReactInstanceForElement这个函数

export function getReactInstanceForElement(element) {
  // Prefer React DevTools, which has direct access to `react-dom` for mapping `element` <=> Fiber
  if ('__REACT_DEVTOOLS_GLOBAL_HOOK__' in window) {
    // @ts-expect-error - TS2339 - Property '__REACT_DEVTOOLS_GLOBAL_HOOK__' does not exist on type 'Window & typeof globalThis'.
    const { renderers } = window.__REACT_DEVTOOLS_GLOBAL_HOOK__

    for (const renderer of renderers.values()) {
      try {
        const fiber = renderer.findFiberByHostInstance(element)

        if (fiber) {
          return fiber
        }
      } catch (e) {
        // If React is mid-render, references to previous nodes may disappear during the click events
        // (This is especially true for interactive elements, like menus)
      }
    }
  }

  if ('_reactRootContainer' in element) {
    // @ts-expect-error - TS2339 - Property '_reactRootContainer' does not exist on type 'HTMLElement'.
    return element._reactRootContainer._internalRoot.current.child
  }

  // eslint-disable-next-line guard-for-in
  for (const key in element) {
    // Pre-Fiber access React internals
    if (key.startsWith('__reactInternalInstance$')) {
      return element[key]
    }

    // Fiber access to React internals
    if (key.startsWith('__reactFiber')) {
      return element[key]
    }
  }
}

它会用几种方式来尝试获取Fiber对象,Fiber对象里的_debugSource属性就存储了columnNumber、fileName、lineNumber这些信息,就能拼出跳转所需要的path了。

利用click-to-component查看React Fiber结构,通透直观,浅显易懂!

查看FiberNode

大家平常肯定看过很多八股文,什么FiberNode里有哪些属性啊,hooks为什么用链表存储啊,这些东西说实话知道了意义也不大。用Fiber来模拟函数调用栈是React团队研究了两年多才弄出来的架构,不建议大家看了点文章视频就背来背去面试时互相套路哈。不过作为一个程序员,简单了解一下它是什么还是可以的,而且动手操作了才更有意义。

把跳转的逻辑注释掉,加上打印fiber的代码(因为我装了React DevTools插件所以就在第一个分支里加了)

利用click-to-component查看React Fiber结构,通透直观,浅显易懂!

利用click-to-component查看React Fiber结构,通透直观,浅显易懂!

再随便改改next/pages下index.tsx的内容

'use client'

import type { NextPage } from 'next'
import styles from '../styles/Home.module.css'
import { useState, useRef } from 'react'

const Home: NextPage = () => {
  const [a, setA] = useState(0)
  const [b, setB] = useState(10)
  const handleClick = () => {
    setA(a + 1)
    setB(b + 1)
  }

  const testRef = useRef('as')
  return (
    <div className={styles.container}>
      <p>{a}</p>
      <p>{b}</p>
      <button onClick={handleClick}>add</button>
    </div>
  )
}

export default Home

到页面上,按住option/alt+左键,按照原来的方式使用click-to-component,终于见到FiberNode真容了。

利用click-to-component查看React Fiber结构,通透直观,浅显易懂!

看下hooks的保存方式(用到了useState和useRef)

利用click-to-component查看React Fiber结构,通透直观,浅显易懂!

改变一下a,b的值,然后查看对应fiber的alternate属性

利用click-to-component查看React Fiber结构,通透直观,浅显易懂! 利用click-to-component查看React Fiber结构,通透直观,浅显易懂!

加两个useEffect,看看它们的环形链表结构

利用click-to-component查看React Fiber结构,通透直观,浅显易懂!

差不多就按这个思路可以逐步探索React Fiber了,赶快动手试试吧!

转载自:https://juejin.cn/post/7367174168600150026
评论
请登录