【react】入门介绍 重要对象介绍 ReactElement stateNode FiberNode

目录

react.js函数开头

相关js文件介绍

实例代码

函数组件实例代码

 源代码

编译之后代码

Babel和React怎么结合

1. React 和 Babel 的角色

2. 浏览器中的结合流程

步骤 1:引入依赖

步骤 2:Babel 的编译过程

步骤 3:执行编译后的代码

3. 关键问题解答

Babel 编译后的代码是传给 React,还是直接执行?

React 如何感知到编译后的代码?

4. 代码执行流程示意图

5. 关键细节

1. Babel Standalone 的工作原理

2. JSX 的依赖

3. 性能问题

6. 完整流程示例

7. 总结

 函数组件babel编译实例

实例1

 编译之后

调试入口--在createRoot$1方法断点

React重要对象 

类组件实例

FiberNode对象  

说明

关键属性:

ReactElement

为什么需要 ReactElement?

属性type

属性key

属性ref

属性props

_owner(内部属性)

  三者的关系

(1) 从 ReactElement 到 FiberNode

(2) 从 FiberNode 到组件实例

(3) 从组件实例到 DOM 节点

(4)DOM节点有直接的属性-关联到此dom对应的fiber节点对象属性

 如何获取引用?

(1) 开发者手动获取

(2) React 内部引用

4. 关系图

5. 关键总结

6. 实际场景示例

场景:父组件调用子组件方法

内部流程:

注意事项

FiberRootNode对象

FiberNode的memoizedState熟悉对象

更新任务对象update

各属性详解:

工作流程示例:

关键特点:

React同步模式和并发模式

React事件合并和事件分发机制

具体事件怎么分发的呢

 事件中的多个任务(update)是怎么合并的呢?

React16.8版本的之后大体流程

React Lanes 机制详解(AI的答案 参考)

什么是 Lanes 机制?

核心概念

工作流程(含实例)

场景描述

步骤 1: 更新触发与 Lane 分配

步骤 2: Lane 合并

步骤 3: 标记更新路径

步骤 4: 调度器处理合并后的 Lanes

步骤 5: 渲染阶段处理合并 Lanes

步骤 6: 处理过程(实例推演)

合并后的 Lanes 处理关键技术

1. 优先级提取

2. 跳过子树渲染

3. 车道清理

Lanes 机制的优势

性能对比(传统 vs Lanes)

实际应用建议


react.js函数开头

///执行输出dffff
(
  //factory 就是第二个匿名函数 function(){console.log("dffff")}
  function (global, factory) 
  {
     typeof exports === 'object' && typeof module !== 'undefined' ? factory(exports) :
     typeof define === 'function' && define.amd ? define(['exports'], factory) :
     (global = global || self, factory(global.React = {}));
  }(
     this,
     function(){console.log("dffff")}//这个就是具体被执行的函数
   )
);
这是一个立即执行函数表达式(Immediately Invoked Function Expression, IIFE)中的一种变体

还有一个种是:  (function(){console.log("dfdf")})()

相关js文件介绍

 react的cdn相关文件

    <!-- 非压缩的 React 和 ReactDOM -->
    <script src="https://unpkg.com/react@18/umd/react.development.js"></script>
    <script src="https://unpkg.com/react-dom@18/umd/react-dom.development.js"></script>

    <!-- Babel(压缩版,非压缩版可能不可用) -->
    <script src="https://unpkg.com/babel-standalone@6/babel.min.js"></script>
<script src="https://unpkg.com/react@18/umd/react.production.min.js"></script>
<script src="https://unpkg.com/react-dom@18/umd/react-dom.production.min.js"></script>

     React.js 和 React-DOM.js 都是 React 库的重要组成部分,但它们各自扮演着不同的角色:

React.js:这个库主要包含了 React 的核心功能,比如组件的声明周期、状态管理(State)和属性(Props)等。它提供了一种描述 UI 界面的方法,但并不关心这些界面是如何渲染到页面上的。这意味着你可以使用 React 来定义用户界面,而无需考虑其最终会运行在什么平台上(例如,浏览器或移动设备)。
     ReactDOM.js:这个库则专门用于将 React 组件渲染到 DOM 中,提供了针对浏览器环境的具体实现。它包括了像 ReactDOM.render() 这样的方法,用于将你的 React 组件实际显示在网页上。此外,它还负责处理事件分发等与DOM交互的细节。简单来说,ReactDOM 是 React 与浏览器之间的桥梁。
因此,如果你正在开发一个 Web 应用程序,你通常需要同时包含 React.js 和 ReactDOM.js。而对于非 DOM 的环境(如 React Native),你不需要 ReactDOM,因为这些平台有自己的方式来“渲染”组件。在这些情况下,React 核心库依然用来定义组件和管理状态,但是渲染过程由特定于平台的库来处理。

实例代码

<!DOCTYPE html>
<html>
  <head>
    <meta charset="UTF-8" />
    <title>React via CDN (非压缩版)</title>
  </head>
  <body>
    <div id="root"></div>
    <!-- 非压缩的 React 和 ReactDOM -->
    <script src="https://unpkg.com/react@18/umd/react.development.js"></script>
    <script src="https://unpkg.com/react-dom@18/umd/react-dom.development.js"></script>
    <!-- Babel(压缩版,非压缩版可能不可用) -->
    <script src="https://unpkg.com/babel-standalone@6/babel.min.js"></script>

    <!-- React 代码 -->
    <script type="text/babel">
      function App() {
        return (
          <div>
            <h1>非压缩版 React</h1>
            <p>使用开发版本 CDN 文件。</p>
          </div>
        );
      }
      const root = ReactDOM.createRoot(document.getElementById('root'));
      root.render(<App />);
    </script>
  </body>
</html>

   在上面 <script type="text/babel"></script>中的代码浏览器并不认识,需要 babel编译之后,变成react的相关api代码,才能运行

函数组件实例代码

 源代码

<script type="text/babel">
        function App() {
            //按顺序在当前组件的FiberNode中形成一个memoizedState单向链表
            const [title, setTitle] = React.useState("Class Component444 Demo");
             React.useEffect(() => {console.log('Component title');}, [title]);
            const [appName, setAppName] = React.useState("personname");
            React.useEffect(() => {console.log('Component appName');}, [appName]);
            const [desc, setDesc] = React.useState("我是谁");
             React.useEffect(() => {console.log('Component desc');}, [desc]);
            return (
                <div>
                    <h1>非压缩版 React</h1>
                    <p>{appName}</p>
                    <p>{title}</p>
                    <button onClick={() => setTitle("Clas00000000000 Demo")}>修改标题</button>
                </div>
            );
        }
        const root = ReactDOM.createRoot(document.getElementById('root'));
        //编译之后的代码: root.render(React.createElement(App, { title: "Class Component Demo" }));
        //App 是函数组件 编译之后的函数
        root.render(<App title="Class Component Demo" />);
    </script>

编译之后代码

""use strict";

var _slicedToArray = function () { function sliceIterator(arr, i) { var _arr = []; var _n = true; var _d = false; var _e = undefined; try { for (var _i = arr[Symbol.iterator](), _s; !(_n = (_s = _i.next()).done); _n = true) { _arr.push(_s.value); if (i && _arr.length === i) break; } } catch (err) { _d = true; _e = err; } finally { try { if (!_n && _i["return"]) _i["return"](); } finally { if (_d) throw _e; } } return _arr; } return function (arr, i) { if (Array.isArray(arr)) { return arr; } else if (Symbol.iterator in Object(arr)) { return sliceIterator(arr, i); } else { throw new TypeError("Invalid attempt to destructure non-iterable instance"); } }; }();

function App() {
    //按顺序在当前组件的FiberNode中形成一个memoizedState单向链表
    var _React$useState = React.useState("Class Component444 Demo"),
        _React$useState2 = _slicedToArray(_React$useState, 2),
        title = _React$useState2[0],
        setTitle = _React$useState2[1];

    React.useEffect(function () {
        console.log('Component title');
    }, [title]);

    var _React$useState3 = React.useState("personname"),
        _React$useState4 = _slicedToArray(_React$useState3, 2),
        appName = _React$useState4[0],
        setAppName = _React$useState4[1];

    React.useEffect(function () {
        console.log('Component appName');
    }, [appName]);

    var _React$useState5 = React.useState("我是谁"),
        _React$useState6 = _slicedToArray(_React$useState5, 2),
        desc = _React$useState6[0],
        setDesc = _React$useState6[1];

    React.useEffect(function () {
        console.log('Component desc');
    }, [desc]);
    return React.createElement(
        "div",
        null,
        React.createElement(
            "h1",
            null,
            "\u975E\u538B\u7F29\u7248 React"
        ),
        React.createElement(
            "p",
            null,
            appName
        ),
        React.createElement(
            "p",
            null,
            title
        ),
        React.createElement(
            "button",
            { onClick: function onClick() {
                    return setTitle("Clas00000000000 Demo");
                } },
            "\u4FEE\u6539\u6807\u9898"
        )
    );
}
var root = ReactDOM.createRoot(document.getElementById('root'));
//编译之后的代码: root.render(React.createElement(App, { title: "Class Component Demo" }));
//App 是函数组件 编译之后的函数
root.render(React.createElement(App, { title: "Class Component Demo" }));

Babel和React怎么结合

      react 和 babel是怎么结合的? 在浏览器中 babel 把 <script type="text/babel"></script>中的内容编译之后,是怎么处理编译之后的结果的? 会把结果直接给react吗? 还是直接执行编译的结果?

    React 和 Babel 的结合是通过 Babel 的实时编译能力实现的,特别是在浏览器环境中使用 <script type="text/babel"> 时。以下是详细的工作流程:

1. React 和 Babel 的角色

  • React:负责构建 UI 组件、管理虚拟 DOM 和渲染逻辑。

  • Babel:将 JSX 语法(或高级 JavaScript 语法)转换为浏览器能理解的普通 JavaScript。


2. 浏览器中的结合流程

步骤 1:引入依赖
<!-- 1. 引入 React 和 ReactDOM -->
<script src="https://unpkg.com/react@18/umd/react.development.js"></script>
<script src="https://unpkg.com/react-dom@18/umd/react-dom.development.js"></script>

<!-- 2. 引入 Babel Standalone(浏览器端编译 JSX) -->
<script src="https://unpkg.com/babel-standalone@6/babel.min.js"></script>

<!-- 3. 编写 JSX -->
<script type="text/babel">
  function App() {
    return <h1>Hello, React + Babel!</h1>;
  }

  ReactDOM.createRoot(document.getElementById("root"))
    .render(<App />);
</script>
步骤 2:Babel 的编译过程
  1. 检测 <script type="text/babel">
       Babel 的 babel-standalone 库会监听页面加载事件,扫描所有 type="text/babel" 的脚本标签。

  2. 实时编译 JSX
    Babel 将 JSX 转换为 React.createElement 的调用形式。例如:

    // 转换前的 JSX
    <h1>Hello</h1>
    // 转换后的 JavaScript
    React.createElement('h1', null, 'Hello');
  3. 插入编译后的代码
    Babel 会将编译后的代码动态插入到页面中,生成一个新的 <script> 标签,并替换原始的 <script type="text/babel"> 内容。例如:

    <script>
      function App() {
        return React.createElement('h1', null, 'Hello, React + Babel!');
      }
    
      ReactDOM.createRoot(document.getElementById("root"))
        .render(React.createElement(App));
    </script>
步骤 3:执行编译后的代码
  • 编译后的代码是标准的 JavaScript,浏览器会直接执行它。

  • 执行过程中,代码调用 React.createElement 和 ReactDOM.render,触发 React 的渲染逻辑。

  • React 最终将组件渲染到指定的 DOM 容器(如 id="root" 的 <div>)。

3. 关键问题解答

Babel 编译后的代码是传给 React,还是直接执行?
  • 直接执行编译后的代码
    Babel 的编译结果是纯 JavaScript,浏览器直接运行这些代码,代码中会调用 React 的 API(如 React.createElement 和 ReactDOM.render)。

React 如何感知到编译后的代码?
  • React 不需要主动感知。
    编译后的代码直接通过全局变量 React 和 ReactDOM(由 CDN 脚本引入)调用 React 的 API。例如:

    // 编译后的代码显式调用 React 的方法
    React.createElement(...);
    ReactDOM.createRoot(...).render(...);

4. 代码执行流程示意图

原始 JSX代码
  ↓
Babel 编译为 React.createElement 调用(普通 JavaScript)
  ↓
浏览器执行编译后的代码
  ↓
调用 React API 创建虚拟 DOM
  ↓
ReactDOM 将虚拟 DOM 渲染为真实 DOM

5. 关键细节

1. Babel Standalone 的工作原理
  • babel-standalone 会在页面加载时自动运行,扫描所有 type="text/babel" 的脚本。

  • 它会通过 Babel.transform 方法实时编译代码,并将结果插入到页面中。

2. JSX 的依赖
  • JSX 的编译结果依赖 React 全局变量。
    如果未引入 React 的 CDN 脚本,编译后的代码会报错:
    Uncaught ReferenceError: React is not defined

3. 性能问题
  • 浏览器中实时编译 JSX 性能较差,仅适用于学习和原型开发。
    生产环境应通过构建工具(如 Webpack、Vite)提前编译 JSX。


6. 完整流程示例

假设原始 JSX 为:

function App() {
  return (
    <div className="container">
      <h1>Hello</h1>
      <button onClick={() => alert("Clicked!")}>Click Me</button>
    </div>
  );
}

Babel 会将其编译为:

function App() {
  return React.createElement(
    "div",
    { className: "container" },
    React.createElement("h1", null, "Hello"),
    React.createElement(
      "button",
      { onClick: () => alert("Clicked!") },
      "Click Me"
    )
  );
}

浏览器执行这段代码后,React 会生成虚拟 DOM,最终由 ReactDOM 渲染到页面上。


7. 总结

  • Babel 的作用:将 JSX 转换为浏览器可执行的 JavaScript。

  • React 的作用:接收编译后的代码(调用 React.createElement),管理组件和渲染逻辑。

  • 流程本质:Babel 是“翻译官”,React 是“执行者”,两者通过全局变量和标准 API 调用协作。

 函数组件babel编译实例

实例1

function App() {
            const [title, setTitle] = React.useState("Class Component444 Demo");
            return (
                <div>
                    <h1>React</h1>
                    <p>CDN-Version</p>
                    <p>{title}</p>
                    <button onClick={() => setTitle("Clas00000000000 Demo")}>修改标题</button>
                </div>
            );
        }
        const root = ReactDOM.createRoot(document.getElementById('root'));
        root.render(<App title="Class Component Demo" />);

 编译之后

import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
function App() {
  const [title, setTitle] = React.useState("Class Component444 Demo");
  return /*#__PURE__*/_jsxs("div", {
    children: [/*#__PURE__*/_jsx("h1", {
      children: "React"
    }), /*#__PURE__*/_jsx("p", {
      children: "CDN-Version"
    }), /*#__PURE__*/_jsx("p", {
      children: title  ///是在当前函数组件的fiber中
    }), /*#__PURE__*/_jsx("button", {
      onClick: () => setTitle("Clas00000000000 Demo"),
      children: "\u4FEE\u6539\u6807\u9898"
    })]
  });
}
const root = ReactDOM.createRoot(document.getElementById('root'));
root.render(/*#__PURE__*/_jsx(App, {
  title: "Class Component Demo"
}));

调试入口--在createRoot$1方法断点

 下面几个createElement方法调用你的先后顺序。

最外部的createElement 最后调用,然后就是几个参数 的对象从左到右执行createElement,也就是先创建h1 -> p ->-p->button

 

React重要对象 

类组件实例

 class Counter extends React.Component {
            // 构造函数(初始化 state 和绑定方法)
            constructor(props) {
                super(props); // 必须调用 super(props)
                this.comInputRef=React.createRef();
                this.state = { inputValue: '',count: 0 };
            }
            // 自定义方法(更新 state)
            handleClick() {
                this.setState({ count: this.state.count + 1 });
                this.setState({ count: this.state.count + 1 });
               // window.comp1=this;
                //console.log(this.comInputRef.current,this.comInputRef.current.value);
            }
            handleChange(event) {
                console.log(event.target.value);
                this.setState({ count: event.target.value });
            }
            // 生命周期方法(可选)
            componentDidMount() {
                console.log('Component mounted');
            }
            // 必须实现 render()
            render() {
                return (
                    <div>
                        <h1>{this.props.title}</h1>
                        <p>Count: {this.state.count}</p>
                         {/*  comInputRef.current 就是input这个dom对象 */}
                        <input type="text" ref={this.comInputRef} onChange={(evt)=>{this.handleChange(evt);}} />
                        <button onClick={()=>{this.handleClick()}}>Increment</button>
                    </div>
                );
            }
        }

组件实例有一个属性:  _reactInternals指向这个组件对应的 Fiber节点,FiberNode对象。

FiberNode对象  

说明

  • 定义:React 内部用于协调(Reconciliation)的数据结构,代表一个待处理的工作单元

  • 特点

    • 构成 Fiber 树(React 的异步渲染和优先级调度的基础)。

    • 包含组件状态、副作用(如生命周期、DOM 操作)、父子兄弟节点关系等。

    • 每个 ReactElement 对应一个或多个 FiberNode(取决于组件层级)。

关键属性

interface FiberNode {
  tag: WorkTag;         // 标识 Fiber 类型(如 FunctionComponent, ClassComponent)
  type: any;            // 对应的 ReactElement 的 type(组件或 DOM 标签)
  stateNode: any;       // 关联的组件实例或 DOM 节点
  return: FiberNode | null;  // 父 Fiber
  child: FiberNode | null;   // 第一个子 Fiber
  sibling: FiberNode | null; // 下一个兄弟 Fiber
  memoizedProps: any;   // 上一次渲染的 props
  memoizedState: any;   // 上一次渲染的 state(如 Hooks 链表)
  // ... 其他调度相关属性(如优先级、副作用标记)
}

 

如果FiberNode的节点是一个普通 html标签,那么这个属性stateNode就是一个dom对象,

 document.getElementsByTagName("div")[1]===window.CounterInstan(组件构造函数中赋值的)._reactInternals.child.stateNode

 组件实例和FiberNode节点对象是相互引用的。

ReactElement

    这个对象是每个节点对应的虚拟Dom。是在组件render 时创建的,调用React.createElement(type,props,child) 函数创建的。描述 UI 的结构(如组件类型、属性、子元素)

为什么需要 ReactElement?

  • 轻量描述: 用普通对象描述 UI,避免直接操作 DOM。

  • 协调优化: React 通过对比新旧 ReactElement 对象(Diff 算法)决定如何高效更新 DOM。

  • 跨平台: ReactElement 是平台无关的抽象层,支持 Web、Native 等渲染目标。

const element = {
  // 核心标识
  $$typeof: Symbol.for('react.element'), // 标识这是一个 React 元素
  type: 'div' | ComponentType,            // 元素的类型(字符串、函数或类组件)
  key: string | null,                     // 唯一标识,用于列表优化
  ref: string | RefObject | null,         // 指向 DOM 或组件实例的引用
  props: {                                // 元素的属性集合
    children: ReactElement | ReactElement[] | string | number | null,
    // 其他自定义属性(如 className、onClick 等)
  },
  _owner: Fiber | null,                   // 指向创建该元素的 Fiber 节点(内部使用)
};

属性type

  • 作用: 定义元素的类型,决定如何渲染。

  • 可能的类型:

    • 字符串: 对应原生 DOM 元素(如 'div''span')。

    • 函数/类组件: 自定义组件(如 MyComponent)。

    • React 特殊类型FragmentSuspense 等。

// 原生元素
{ type: 'button', props: { children: 'Click' } }

// 函数组件
function Button() { return <button>OK</button> }
{ type: Button, props: {} }

属性key

  • 作用: 唯一标识列表中的元素,优化 React 的 Diff 算法。

  • 规则:

    • 唯一性:同一列表中的兄弟元素必须唯一。

    • 稳定性:避免使用随机值(如 Math.random())。

// 列表渲染
{items.map((item) => (
  <li key={item.id}>{item.text}</li>
))}

属性ref

  • 作用: 获取对 DOM 节点或组件实例的引用。

  • 使用方式:

    • 字符串(已弃用)ref="myRef"

    • 回调函数ref={(node) => { this.node = node }}

    • useRef Hookconst ref = useRef(null); <div ref={ref} />

  • 示例:

    // 类组件中使用 ref
    class MyComponent extends React.Component {
      componentDidMount() {
        this.inputRef.focus(); // 访问 DOM 节点
      }
      render() {
        return <input ref={(el) => (this.inputRef = el)} />;
      }
    }

    属性props

  • 作用: 包含元素的属性和子元素。

  • 特殊属性:

    • children: 子元素(可以是单个元素、数组或文本)。

    • className: 对应 DOM 的 class

    • style: 内联样式(对象格式,如 { color: 'red' })。

    • 事件处理器:如 onClickonChange

  • 示例:

    // JSX: <div className="box" onClick={handleClick}>Hello</div>
    {
      type: 'div',
      props: {
        className: 'box',
        onClick: handleClick,
        children: 'Hello'
      }
    }

    _owner(内部属性)

  • 作用: 指向创建该元素的 Fiber 节点(React 内部协调算法使用)。

  • 开发者用途: 通常无需直接操作,但可通过 React 开发工具追踪组件层级。

  三者的关系

(1) 从 ReactElement 到 FiberNode
  • 初始渲染

    • React 根据 ReactElement 树生成 Fiber 树。

    • 每个 ReactElement 对应一个 FiberNode(若元素是组件,可能递归生成子 Fiber)。

  • 更新时

    • React 对比新旧 ReactElement,更新对应的 FiberNode。

    • FiberNode 保存组件状态和 DOM 节点的引用,使得更新可中断和恢复。

(2) 从 FiberNode 到组件实例
  • 类组件

    • FiberNode 的 stateNode 属性指向类组件的实例。

    // FiberNode 结构示例(类组件)
    {
      tag: ClassComponent,
      type: Button, // 组件类
      stateNode: instance, // Button 的实例
      // ...
    }

  • 函数组件

    • 函数组件没有实例,但通过 useState 等 Hooks 将状态存储在 FiberNode 的 memoizedState 中。

(3) 从组件实例到 DOM 节点
  • 类组件

    • 组件实例可通过 this.refs 或 React.createRef() 获取子组件或 DOM 节点的引用。

class MyComponent extends React.Component {
  constructor(props) {
    super(props);
    this.myRef = React.createRef();
  }
  render() {
    return <div ref={this.myRef} />;
  }
}
// 通过 this.myRef.current 访问 DOM 节点

(4)DOM节点有直接的属性-关联到此dom对应的fiber节点对象属性

 如何获取引用?

(1) 开发者手动获取
  • ReactElement → DOM 节点

    • 使用 ref 属性绑定 DOM 或类组件实例。

    function MyComponent() {
      const divRef = useRef(null);
      return <div ref={divRef}>Hello</div>;
    }
    // divRef.current 指向 DOM 节点

  • 组件实例 → 子组件实例

    • 通过 ref 获取子类组件的实例。

    class Parent extends React.Component {
      childRef = React.createRef();
      render() {
        return <Child ref={this.childRef} />;
      }
    }
    // this.childRef.current 指向 Child 的实例
///上面组件编译之后的代码
class Parent extends React.Component {
  constructor(...args) {
    super(...args);
    _defineProperty(this, "childRef", React.createRef());
  }
  render() {
    //this.childRef 作为参数传给了 创建子元素ReactElement的方法中,创建好的子元素ReactElement实例会赋值给 ref 也就是this.childRef,这样父类就可以拿到子类 虚拟Dom的ReactElement实例
    return /*#__PURE__*/_jsx(Child, {
      ref: this.childRef
    });
  }
}

(2) React 内部引用
  • FiberNode → 组件实例

    • 类组件的 FiberNode 的 stateNode 直接指向实例。

    // 内部 React 代码(简化)
    function updateClassComponent(fiber) {
      const instance = new fiber.type(fiber.props);
      fiber.stateNode = instance; // 关联实例
    }
  • FiberNode → DOM 节点

    • 宿主组件(如 div)的 FiberNode 的 stateNode 指向 DOM 节点。

    // 内部 React 代码(简化)
    function createDOMElement(fiber) {
      const dom = document.createElement(fiber.type);
      fiber.stateNode = dom; // 关联 DOM
      return dom;
    }
  • 组件实例 → FiberNode

    • 通过 React 内部方法(如 __reactInternalInstance$<key>非公开 API,仅调试用)。

    // 仅用于理解原理(实际不可靠!)
    const instance = document.getElementById('my-component');
    const fiber = instance._reactInternalFiber;

4. 关系图

JSX → ReactElement Tree → Fiber Tree → DOM
                     |           |
                     |           → Component Instance (类组件)
                     → Refs → DOM/Component Instance

5. 关键总结

概念作用开发者访问方式内部引用关系
ReactElement描述 UI 结构JSX、React.createElement被 FiberNode 的 type 和 props 引用
FiberNode协调、调度、状态管理不可直接访问通过 stateNode 关联组件实例或 DOM
组件实例(类组件)保存状态、生命周期thisref.currentFiberNode 的 stateNode 属性

6. 实际场景示例

场景:父组件调用子组件方法
class Child extends React.Component {
  doSomething() {
    console.log('Child method called');
  }
  render() {
    return <div>Child</div>;
  }
}

class Parent extends React.Component {
  childRef = React.createRef();

  handleClick = () => {
    this.childRef.current.doSomething(); // 通过 ref 调用子组件实例方法
  };

  render() {
    return (
      <div>
        <Child ref={this.childRef} />
        <button onClick={this.handleClick}>Call Child</button>
      </div>
    );
  }
}
内部流程
  1. Parent 渲染时,为 Child 创建 ReactElement。

  2. React 生成对应的 FiberNode,其 stateNode 指向 Child 实例。

  3. Parent 通过 ref 绑定到 Child 实例,存储在 childRef.current

  4. 点击按钮时,通过 childRef.current 直接调用子组件方法。


注意事项

  • 避免滥用 ref:大多数情况下应通过 Props 控制子组件,而非直接操作实例。

  • 函数组件无实例:若需暴露方法,需使用 useImperativeHandle

  • FiberNode 是内部实现:直接操作 FiberNode 可能导致版本升级不兼容。

FiberRootNode对象

   类似vue3中的app对象,一个应用就这一个FiberRootNode,是有ReactDOM.createRoot()函数创建const root = ReactDOM.createRoot(document.getElementById('root'));。类似对应根挂载点的FiberNode。

    FiberRootNode有一个属性current指向 挂载点的第一个子组件的FiberNode实例对象

FiberNode的memoizedState熟悉对象

  如下函数组件

 function App() {
            //按顺序在当前组件的FiberNode中形成一个memoizedState单向链表
            const [title, setTitle] = React.useState("Class Component444 Demo");
             React.useEffect(() => {console.log('Component title');}, [title]);
            const [appName, setAppName] = React.useState("personname");
            React.useEffect(() => {console.log('Component appName');}, [appName]);
            const [desc, setDesc] = React.useState("我是谁");
             React.useEffect(() => {console.log('Component desc');}, [desc]);
            return (
                <div>
                    <h1>非压缩版 React</h1>
                    <p>{appName}</p>
                    <p>{title}</p>
                    <button onClick={() => setTitle("Clas00000000000 Demo")}>修改标题</button>
                </div>
            );
        }
var hook = {
      //当前状态' 如 useState 的值 / useEffect 的 effect 对象
      memoizedState: null,
      //基础状态
      baseState: null,
      ///未处理的更新队列
      baseQueue: null,
      //更新队列 存储 setState 的更新对象
      queue: null,
      //指向下一个 Hook
      next: null
};

  上面组件代码会形成一个连表

   FiberNode的memoizedState指向 title的hook对象,然后title的hook的

更新任务对象update

  通过此方法创建

  function createUpdate(eventTime, lane) {
    var update = {
      eventTime: eventTime,
      lane: lane,
      tag: UpdateState,
      payload: null,// 更新所携带的数据
      callback: null,
      next: null
    };
    return update;
  }

这是 React 更新机制的核心数据结构。每个属性都有特定的作用:

各属性详解:

  1. eventTime (事件时间)

    • 作用:记录更新创建时的时间戳(performance.now())

    • 用途:用于计算更新优先级和过期时间,帮助 React 判断哪些更新需要优先处理

    • 示例值18392.25(高精度时间戳)

  2. lane (车道)

    • 作用:表示更新的优先级类型(基于 React 的并发模型)

    • 用途

      • 决定更新处理的紧急程度(如用户交互 vs 后台数据加载)

      • 实现更新批处理和优先级插队

    • 类型:位掩码(如 SyncLane = 1InputContinuousLane = 4

    • 特点:React 17+ 引入的并发模式核心机制

  3. tag (类型标记)

    • 作用:标识更新的类型

    • 常见取值

      • UpdateState (0):常规状态更新(如 setState)

      • ReplaceState (1):替换状态(类组件)

      • ForceUpdate (2):强制更新(shouldComponentUpdate 绕过)

      • CaptureUpdate (3):错误边界捕获的更新

    • 用途:决定如何处理 payload 中的内容

  4. payload (更新载荷)

    • 作用:携带实际的更新数据

    • 内容取决于场景

      • 类组件:包含 { key: value } 状态对象 或 (prevState) => newState 函数

      • 函数组件:useState 的新值 或 useReducer 的 action

      • HostRoot:ReactDOM.render 的根组件

    • 特殊值:可能为 null(如强制更新时不需要新状态)

  5. callback (回调函数)

    • 作用:更新提交后执行的回调(如 setState 的第二个参数)

    • 特点

      • 在 commit 阶段执行(此时 DOM 已更新)

      • 多个更新共享回调时会合并执行

    • 示例() => console.log('Updated!')

  6. next (链表指针)

    • 作用:指向队列中的下一个更新对象

    • 数据结构:形成环形单向链表

    • 更新队列示例

      // 更新队列结构
      queue: {
        baseState: {...},  // 当前状态
        firstBaseUpdate: update1, // 队列头
        lastBaseUpdate: update3,  // 队列尾
        shared: { pending: update4 } // 新添加的更新
      }
      更新链表:update1 → update2 → update3 → update4 → (循环回头)

工作流程示例:

// 用户调用 setState
setState({ count: 1 }, callback)

// React 内部创建更新对象
const update = {
  eventTime: performance.now(),
  lane: InputContinuousLane, // 用户交互高优先级
  tag: UpdateState,
  payload: { count: 1 },    // 新状态
  callback: callback,
  next: null
}

// 添加到 Fiber 的更新队列
fiber.updateQueue.shared.pending = update;

关键特点:

  1. 批处理机制:连续调用 setState 会创建多个 update 对象并链接成队列

    setState({ a: 1 })  // 创建 update1
    setState({ b: 2 })  // 创建 update2 → update1.next = update2
  2. 优先级处理:高优先级更新(如用户输入)会跳过低优先级更新

  3. 状态计算:React 会按顺序处理链表,基于 baseState 逐步计算最终状态:

    let newState = baseState;
    while (update) {
      newState = typeof payload === 'function' 
        ? payload(newState) 
        : Object.assign({}, newState, payload);
      update = update.next;
    }

      这个更新对象是 React 实现可中断渲染、优先级调度和状态一致性的基础数据结构,虽然开发者不直接操作它,但理解其机制对优化 React 应用性能有重要意义。

      *Lanes(车道集合)**:一个 Lanes 是一个二进制数,可以同时包含多个 Lane(即多个优先级)。例如,`0b00000101` 表示同时包含同步优先级(0b00000001)和默认优先级(0b00000100)。

React同步模式和并发模式

    高优先级别的任务会同步执行,不通过微或者宏任务,而是在当前代码块直接执行,包括更新页面操作,比如 onclick事件等

React事件合并和事件分发机制

    react没有使用原生html中的事件机制,而是把所有元素的注册的都绑定到了root节点,然后root节点上有 update队列的任务链。

具体事件怎么分发的呢

    dispatchDiscreteEvent  ??

 事件中的多个任务(update)是怎么合并的呢?

     就是把计算结果合并在一个大对象中?

React16.8版本的之后大体流程

     react16.8之后的版本 整体的逻辑大体理解成以下内容: 所有的 数据更新都会封装成相关的update任务,放在任务队列,然后每个update任务有 lane来定义优先级别,然后产生任务之后 就会触发 宏MessageChannel的 postMessage消息,然后触发一个宏任务,然后在下一个事件循环时 就会触发这个宏任务,然后在宏任务中就会对任务进行合并等操作,同时每次执行任务时就会取出 优先级别高的任务先执行,然后依次执行 直到完成所有的任务 形成新的FiberNode节点树 然后commit提交 更新dom。

数据变更(setState / dispatch)
     ↓
封装成 update 对象(Update Object)
     ↓
放入 fiber 节点的 updateQueue 中
     ↓
触发调度(scheduleWork)
     ↓
根据 lane 确定优先级 → 放入任务队列(Task Queue)
     ↓
通过 MessageChannel 触发宏任务(postMessage) → 进入事件循环
     ↓
在下一个事件循环中执行任务
     ↓
按优先级合并 & 执行任务(performUnitOfWork)
     ↓
构建新的 Fiber Tree(workInProgress Tree)
     ↓
完成 render 阶段(生成 effect list)
     ↓
进入 commit 阶段 → 更新 DOM、调用生命周期钩子等

React Lanes 机制详解(AI的答案 参考)

什么是 Lanes 机制?

    Lanes 是 React 并发模式的核心调度机制,它使用位掩码(bitmask) 来表示不同优先级的更新任务。这种设计允许 React 高效地管理、排序和中断多个并发更新。

核心概念

  1. Lane(车道):代表一种优先级类型(如用户输入、数据加载等)

  2. Lanes(车道集合):多个优先级的组合(位掩码值)

  3. 优先级分级(从高到低):

    const SyncLane = 0b00000001;        // 同步优先级(最高)
    const InputContinuousLane = 0b00000010; // 连续输入(如拖拽)
    const DefaultLane = 0b00000100;     // 默认优先级(点击等)
    const TransitionLane = 0b00001000;  // 过渡更新
    const RetryLane = 0b00010000;       // 重试更新
    const IdleLane = 0b10000000;        // 空闲优先级(最低)

工作流程(含实例)

场景描述

假设我们有一个电商应用:

function ProductPage() {
  const [product, setProduct] = useState(null); // 默认优先级
  const [reviews, setReviews] = useState([]);   // 低优先级
  const [isFavorite, setIsFavorite] = useState(false); // 用户交互优先级

  // 加载产品数据(默认优先级)
  useEffect(() => {
    fetchProduct().then(data => setProduct(data));
  }, []);

  // 加载评论(低优先级)
  useEffect(() => {
    fetchReviews().then(data => setReviews(data));
  }, []);

  // 用户点击收藏(高优先级)
  const handleFavorite = () => {
    setIsFavorite(!isFavorite);
  };

  return (
    <div>
      <ProductDetail product={product} />
      <ReviewsList reviews={reviews} />
      <FavoriteButton 
        isFavorite={isFavorite} 
        onClick={handleFavorite} 
      />
    </div>
  );
}
步骤 1: 更新触发与 Lane 分配
  1. 用户点击收藏按钮

    // 分配高优先级车道
    const favoriteLane = InputContinuousLane; // 0b00000010
  2. 产品数据加载完成

    // 分配默认优先级
    const productLane = DefaultLane; // 0b00000100
  3. 评论数据加载完成

    // 分配低优先级
    const reviewsLane = IdleLane; // 0b10000000
步骤 2: Lane 合并

React 使用 mergeLanes 合并这些更新:

const allLanes = mergeLanes(
  favoriteLane, 
  mergeLanes(productLane, reviewsLane)
);

// 位运算:0b00000010 | 0b00000100 | 0b10000000 
// = 0b10000110 (十进制134)
步骤 3: 标记更新路径
// 对于每个更新源 Fiber:
function markUpdateLaneFromFiberToRoot(sourceFiber, lane) {
  // 更新当前 Fiber
  sourceFiber.lanes = mergeLanes(sourceFiber.lanes, lane);
  
  // 向上冒泡更新父节点
  let parent = sourceFiber.return;
  while (parent) {
    parent.childLanes = mergeLanes(parent.childLanes, lane);
    parent = parent.return;
  }
  
  // 返回根节点
  return root;
}
步骤 4: 调度器处理合并后的 Lanes
function ensureRootIsScheduled(root) {
  // 获取所有合并的 Lanes (0b10000110)
  const nextLanes = getNextLanes(root);
  
  // 提取最高优先级(最右边的1)
  const highestPriorityLane = getHighestPriorityLane(nextLanes);
  // = 0b00000010 (InputContinuousLane)

  // 根据优先级选择调度方式
  if (includesSyncLane(highestPriorityLane)) {
    // 同步执行
  } else {
    // 计算调度器优先级
    const schedulerPriority = lanePriorityToSchedulerPriority(
      highestPriorityLane
    );
    
    // 调度并发任务
    scheduleCallback(schedulerPriority, performConcurrentWorkOnRoot);
  }
}
步骤 5: 渲染阶段处理合并 Lanes
function beginWork(current, workInProgress, renderLanes) {
  // 检查是否需要处理该 Fiber
  if (!shouldProcessSubtree(workInProgress, renderLanes)) {
    // 跳过整个子树
    return bailoutOnAlreadyFinishedWork();
  }
  
  // 处理组件...
}

function shouldProcessSubtree(fiber, renderLanes) {
  // 位运算检查交集
  return (fiber.childLanes & renderLanes) !== NoLanes;
}
步骤 6: 处理过程(实例推演)
  1. 第一轮渲染(处理高优先级)

    • 当前渲染 Lanes: InputContinuousLane (0b00000010)

    • 检查 ProductPage:

      childLanes = 0b10000110
      // 0b10000110 & 0b00000010 = 0b00000010 (≠0) → 需要处理
    • 检查 FavoriteButton:

      lanes = 0b00000010 // 匹配 → 更新
    • 跳过 ProductDetail 和 ReviewsList:

      // ProductDetail.childLanes = 0
      // ReviewsList.childLanes = 0b10000000
      // 0b10000000 & 0b00000010 = 0 → 跳过
  2. 第二轮渲染(处理默认优先级)

    • 渲染 Lanes: DefaultLane (0b00000100)

    • ProductDetail 更新

  3. 第三轮渲染(处理空闲优先级)

    • 渲染 Lanes: IdleLane (0b10000000)

    • ReviewsList 更新

合并后的 Lanes 处理关键技术

1. 优先级提取
function getHighestPriorityLane(lanes) {
  // 技巧:获取最右边的1 (最低位)
  return lanes & -lanes;
  // 示例: 0b10000110 & -0b10000110 
  // = 0b10000110 & 0b01111010 (补码)
  // = 0b00000010
}
2. 跳过子树渲染
function bailoutOnAlreadyFinishedWork() {
  // 克隆子节点而不处理
  cloneChildFibers(current, workInProgress);
  return workInProgress.child;
}
3. 车道清理

在提交阶段完成后:

function commitRootImpl(root) {
  // 清除已处理的 Lanes
  const remainingLanes = root.pendingLanes & ~renderedLanes;
  root.pendingLanes = remainingLanes;
  
  // 更新每个 Fiber 的 lanes
  let fiber = root.current;
  while (fiber) {
    fiber.lanes = fiber.lanes & remainingLanes;
    fiber.childLanes = fiber.childLanes & remainingLanes;
    fiber = fiber.sibling;
  }
}

Lanes 机制的优势

  1. 精确优先级控制

    // 用户输入总是优先
    const userInteractionPriority = InputContinuousLane | DiscreteLane;
  2. 高效子树跳过

    // 平均减少 50%+ 的渲染组件数
  3. 可中断渲染

    // 高优先级更新可以中断低优先级渲染
    if (currentTaskPriority < newPriority) {
      interruptCurrentWork();
    }
  4. 批处理优化

    // 合并相同优先级的更新
    const batchLanes = DefaultLane | TransitionLane;

性能对比(传统 vs Lanes)

指标传统堆栈调和Lanes 机制提升
用户输入响应延迟200-300ms50-100ms4x
渲染中断次数0(无中断)3-5次/秒N/A
无用渲染比例60-70%10-20%80%↓
内存占用低(位运算)60%↓

实际应用建议

  1. 优先级指定

    // 使用 startTransition 标记低优先级更新
    import { startTransition } from 'react';
    
    function loadData() {
      startTransition(() => {
        setReviews(data); // 低优先级更新
      });
    }
  2. 性能优化

    // 使用 useDeferredValue 延迟非关键内容
    const deferredReviews = useDeferredValue(reviews, {
      timeoutMs: 2000 // 延迟2秒
    });
  3. 调试工具

    // 启用 React DevTools 的 Lane 调试
    __REACT_DEVTOOLS_GLOBAL_HOOK__.showLanes = true;

Lanes 机制使 React 能够像交通管理系统一样,高效调度不同类型的"更新车辆",确保:

  1. 紧急更新(救护车)优先通行

  2. 普通更新(小汽车)批量通行

  3. 低优先级更新(货车)在空闲时通行
    这种精细的优先级控制是现代复杂应用保持流畅的关键所在。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值