前端

漫游 React 源码 - 01 - 架构和目录结构

React 架构

React 架构主要分为三部分:

  • Reconciler(协调器):负责比较虚拟 DOM 和真实 DOM,找出差异,然后更新真实 DOM。
  • Renderer(渲染器):负责将虚拟 DOM 渲染到真实 DOM。
  • Scheduler(调度器):负责调度任务,确保任务按优先级执行。

这三部分协同工作,Reconciler找出需要更新的内容,Scheduler安排更新的优先级和时机,Renderer最终将更新渲染到UI上。

React 源码目录结构

  1. packages/:

    • React 代码库的主要目录,包含了 React 的所有包和模块。主要的子目录包括:

      • react: 核心 React 包,包含 React 的主要功能实现。
      • react-dom: 处理与 DOM 交互的包。
      • react-reconciler: 负责协调虚拟 DOM 和真实 DOM。
      • scheduler: 任务调度器,用于控制更新的优先级。
  2. scripts/:

    • 包含了用于构建、测试和发布 React 的脚本。
  3. fixtures/:

    • 包含了 React 的示例和测试用例,通常用于验证和展示 React 的功能。

基本结构

列出一些重要的数据结构和方法,之后可以随时回来查阅。

Fiber

从 React 16 开始,React 引入了 Fiber 架构,用于解决之前版本中存在的性能问题。Reconciler 就是是基于 Fiber 架构实现的。 Fiber 是 React 对组件更新过程进行分片和优先级管理的基础单元,每个 Fiber 代表组件树中的一个节点,不仅包含了组件的相关属性,还有更新队列、更新优先级等信息。

export type Fiber = { // 用于标识 Fiber 类型的标签。 tag: WorkTag, // 标识 Fiber 类型的标签(例如 FunctionComponent、ClassComponent 等)。 key: null | string, // 用于在同一层级的子节点中唯一标识 Fiber 节点。 elementType: any, // Fiber 节点对应的 React 元素类型。 type: any, // Fiber 节点的组件类型或元素类型。div,span stateNode: any, // Fiber 节点的本地状态,对于类组件是组件实例,对于 DOM 节点是实际的 DOM 节点。 return: Fiber | null, // 指向父节点的指针。 child: Fiber | null, // 指向第一个子节点的指针。 sibling: Fiber | null, // 指向下一个兄弟节点的指针。 index: number, // 子节点在父节点中的位置索引。 ref: | null | (((handle: mixed) => void) & { _stringRef: ? string, ... }) // React ref 对象。 | RefObject, refCleanup: null | (() => void), // 用于清理 ref 的回调。 pendingProps: any, // 传入的 props,表示即将生效的属性。 memoizedProps: any, // 之前的 props updateQueue: mixed, // 状态更新队列,存储组件状态的更新。 memoizedState: any, // 记录的状态,表示上一次渲染的组件状态。 dependencies: Dependencies | null, // 组件的上下文依赖,通常用于 Context API。 mode: TypeOfMode, // Fiber 模式标志,用于启用如异步渲染等模式。 // Effect flags: Flags, // 用于标记副作用的标志位。 subtreeFlags: Flags, // 子树中需要处理的副作用标志。 deletions: Array < Fiber > | null, // 需要删除的子节点数组。 // 该 Fiber 节点所属的更新优先级。 lanes: Lanes, // 更新优先级,标记该 Fiber 对应的更新在哪条“车道”中。是number类型 childLanes: Lanes, // 子节点的更新优先级。 alternate: Fiber | null, // 备用 Fiber,指向该 Fiber 的上一次渲染版本。 actualDuration ? : number, // 当前更新过程中此 Fiber 的实际渲染时间。 actualStartTime ? : number, // 此 Fiber 开始渲染的时间。 selfBaseDuration ? : number, // 记录此 Fiber 最近一次渲染的基础时间(不考虑 bailout)。 treeBaseDuration ? : number, // 记录整个子树的基础渲染时间。 // 概念上的别名 // workInProgress : Fiber -> alternate。备用的 Fiber 与工作中的 Fiber 相同。 // 即“双缓存” };

FiberRoot

FiberRoot 是 React 应用的根节点,包含了应用的整个状态和上下文。

// react/src/react-reconciler/src/ReactFiberRoot.js export type FiberRoot = { ...BaseFiberRootProperties, ...SuspenseCallbackOnlyFiberRootProperties, ...UpdaterTrackingOnlyFiberRootProperties, ...TransitionTracingOnlyFiberRootProperties, ... }; type BaseFiberRootProperties = { tag: RootTag, // 根节点的类型(legacy, batched, concurrent 等) containerInfo: Container, // 与该根节点相关联的宿主环境的附加信息 pendingChildren: any, // 仅用于持久更新 // 顶层上下文对象,用于 renderSubtreeIntoContainer context: Object | null, // 用于创建一个链表,表示所有有待处理工作调度的根节点。 next: FiberRoot | null, // 表示当前显示的 UI 树的根节点 current: Fiber, // 表示已完成的 work-in-progress HostRoot,已准备好提交。 finishedWork: Fiber | null, // Scheduler.scheduleCallback 返回的节点。表示根节点将处理的下一个渲染任务。 callbackNode: any, callbackPriority: Lane, expirationTimes: LaneMap < number > , hiddenUpdates: LaneMap < Array < ConcurrentUpdate > | null > , pendingLanes: Lanes, suspendedLanes: Lanes, pingedLanes: Lanes, expiredLanes: Lanes, errorRecoveryDisabledLanes: Lanes, shellSuspendCounter: number, finishedLanes: Lanes, entangledLanes: Lanes, entanglements: LaneMap < Lanes > , pooledCache: Cache | null, pooledCacheLanes: Lanes, };

React. Component

Component 是所有类组件的基类。它提供了组件的生命周期方法和状态管理机制。

// react/src/react/src/ReactBaseClasses.js class Component { constructor(props, context, updater) { this.props = props; this.context = context; this.refs = refs; this.updater = updater || ReactNoopUpdateQueue; // 更新队列 } } Component.prototype.setState = function(partialState, callback) { ... this.updater.enqueueSetState(this, partialState, callback, 'setState'); // 将状态更新添加到更新队列中 }; Component.prototype.forceUpdate = function(callback) { this.updater.enqueueForceUpdate(this, callback, 'forceUpdate'); // 将强制更新添加到更新队列中 };

ReactElement

ReactElement 是 React 中用于表示 UI 元素的对象。

// react/src/jsx/ReactJSXElement.js function ReactElement( type, //元素的类型(标签名或组件 key, //唯一标识元素的键,用于优化列表渲染。 _ref, //用于引用 DOM 节点或组件实例的引用。 self, source, owner, props, //元素的属性,包括 children 和其他用户定义的属性。 debugStack, debugTask, ) { ... }
const element = React.createElement( 'div', { className: 'container' }, 'Hello, World!' );
/** * 创建一个 React 元素。 * @param {string | React.ComponentType} type - 元素的类型,可以是标签名或 React 组件。 * @param {object} config - 元素的配置对象,包含属性、事件等。 * @param {...any} children - 元素的子元素。 * @returns {ReactElement} 返回一个 ReactElement 对象。 */ export function createElement(type, config, children) { const props = {}; // 初始化 props 对象, 之后会将 config 和 children 填充到 props 中。 ... }

在React中,会大量使用 if (__DEV__) { ... } ,在开发模式下,会执行一些额外的检查和日志记录,以确保代码的正确性和性能。有助于捕获潜在的 bug,而不影响生产环境。

Previous
React - useTransition