启动 React APP 后经历了哪些过程

本文作者为 360 奇舞团前端开发工程师

前言

本文中使用的React版本为18,在摘取代码的过程中删减了部分代码,具体以源代码为准。

React 18里,通过ReactDOM.createRoot创建根节点。并且通过调用原型链上的render来渲染。 本文主要是从以下两个方法来介绍展开。

import React from 'react';
import ReactDOM from 'react-dom/client';
import App from './App.tsx';

ReactDOM.createRoot(document.getElementById('root')).render(
  <React.StrictMode>
    <App />
  </React.StrictMode>
);

一、createRoot()

createRoot这个方法主要是用来创建FiberRoot(全局唯一,保存全局状态)和RootFiber(是应用里的第一个fiber对象),并将其关系关联起来。主要有以下过程:

  1. 校验container有效性,以及处理options参数

  2. 创建FiberRootrootFiber,并关联起来

  3. 事件代理

  4. 返回ReactDOMRoot实例

function createRoot(
  container: Element | Document | DocumentFragment,
  options?: CreateRootOptions,
): RootType {
  // 校验合法性,以及处理options参数,此处省略
  if (!isValidContainer(container)) {
    //...
  }

  // 调用 createFiberRoot,创建FiberRoot和rootFiber,并关联关系,最终返回FiberRoot。FiberRoot.current = rootFiber; rootFiber.stateNode = FiberRoot;
  const root = createContainer(
    container,
    ConcurrentRoot,
    null,
    isStrictMode,
    concurrentUpdatesByDefaultOverride,
    identifierPrefix,
    onRecoverableError,
    transitionCallbacks,
  );
  
  // 标记container和rootFiber关系  container['__reactContainer$' + randomKey] = root.current
  markContainerAsRoot(root.current, container); 
  
  const rootContainerElement: Document | Element | DocumentFragment =
    container.nodeType === COMMENT_NODE
      ? (container.parentNode: any)
      : container;
  
  listenToAllSupportedEvents(rootContainerElement); // 事件代理

  // 实例化,挂载render,unmount方法
  return new ReactDOMRoot(root); // this._internalRoot = root;
}

关系结构示意图

a1c45080a08ccad53d32b5d98262e03b.png
image.png

二、render()

render主要是通过调用updateContainer,将组件渲染在页面上。

ReactDOMHydrationRoot.prototype.render = ReactDOMRoot.prototype.render = function(
  children: ReactNodeList,
): void {
  const root = this._internalRoot;
  if (root === null) {
    throw new Error('Cannot update an unmounted root.');
  }
  updateContainer(children, root, null, null);
};

updateContainer

updateContainer主要执行了以下步骤:

  1. 获取当前时间eventTime和任务优先级lane,调用createUpdate生成update;

  2. 执行enqueueUpdate将更新添加到更新队列里,并返回FiberRoot;

  3. scheduleUpdateOnFiber 调度更新;

function updateContainer(
  element: ReactNodeList,
  container: OpaqueRoot,
  parentComponent: ?React$Component<any, any>,
  callback: ?Function,
): Lane {
  const current = container.current; // rootFiber
  const eventTime = requestEventTime(); // 更新触发时间
  const lane = requestUpdateLane(current); // 获取任务优先级

  // ... context 处理 

  // 创建update:{eventTime, lane, tag: UpdateState // 更新类型, payload: null, callback: null, next: null, // 下一个更新}
  const update = createUpdate(eventTime, lane); 
  update.payload = {element}; // element首次渲染时为App

  callback = callback === undefined ? null : callback;
  if (callback !== null) {
    update.callback = callback;
  }

  const root = enqueueUpdate(current, update, lane); // 将update添加到concurrentQueues队列里,返回 FiberRoo
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值