前言
本文主要介绍一些 React 的设计思想和相关概念, 不管是想要阅读源码还是想深入了解 React 的同学看过来呀. 欢迎指出错误, 一起探讨一起进步.
React 阅读系列文章
React 源码阅读: 虚拟 DOM 的初始化
项目结构
React 的相关代码都放在 packages 里.
packages ------------------------------- React 实现的相关代码
create-subscription ------------------------- 在组件里订阅额外数据的工具
events -------------------------- React 事件相关
react-art ------------------------- 画图相关库
- react-dom -------------------------- ReactDom
- react-native-renderer ----------------------------- ReactNative
react-reconciler ------------------------ React 调制器
react-scheduler ------------------------ 规划 React 初始化, 更新等等
react-test-renderer ------------------------ 实验性的 React 渲染器
shared ------------------------ 公共代码
simple-cache-provider ------------------------ 为 React 应用提供缓存
复制代码
主要思想和设计原则
组合
React 的主要特性就是各种组合而成的组件. 由不同人编写的组件可以组合使用, 并且实现组件的复用.
时序安排(Scheduling)
React 的初始化, 更新, 移除等等操作并不是同步的, 用户编写的组件 (如 < ReactComponent/>) 或者平台特定组件 (如 < div/>) 这些只是返回需要渲染的信息, 并不是真实 DOM, 我们通常称他们为虚拟 DOM,React 会遍历这颗虚拟 DOM 树来渲染真实的 DOM 树.
而且 setState()也并不是同步的, 他们的多次调用更新会被整合为一次更新, 加入更新队列然后等待更新, 再去渲染真实的 DOM 树, 因为 DOM 型的操作通常是很耗时的, 所以尽量减少 DOM 相关操作.
DOM 之外
React 的一个主要特点为编写的代码可以通过工具 (如 ReactNative,Electron) 在多个平台上运行, 因此渲染出来的元素可能不是 DOM, 因此 React 将他们分为两个模块, 一个模块为 reconciler(调节器), 它根据用户编写的组件转换为 React 可以识别的元素(即虚拟 DOM); 另一个模块为 renderer(渲染器, 分为 DOM 渲染器和 Native 渲染器), 它的作用为根据虚拟 DOM 渲染为平台特定的元素. 这样的好处是可以方便 React 可以在多平台上运行, 而不必太过关注 reconciler 的代码.
相关概念
Fiber
什么是 Fiber?
Fiber 是 React 版本 16 以后的重要概念.
Fiber 的主要目标为:
先暂停目前的工作去处理优先级更高的工作, 然后再回来继续
为不同的工作设定不同优先级
重用之前完成的工作
终止不再需要的工作
我们都知道调用函数时会把它加入执行栈中, 等函数执行完后再退出栈, 那有没有办法可以定制栈的调用以更好地优化渲染 UI 呢? 这就是 Fiber 想要解决的问题, 我们可以称单个 Fiber 为虚拟的栈帧, 它是实现 React 时序安排的关键.
Fiber 的结构
- type Fiber = {|
- // 辨识组件相关的属性
- tag: TypeOfWork,
- key: null | string,
- type: any,
- // 父 Fiber 或者 null
- return: Fiber | null,
- child: Fiber | null,
- sibling: Fiber | null,
- index: number,
- ref: null | (((handle: mixed) => void) & {_stringRef: ?string}) | RefObject,
- memoizedProps: any, // The props used to create the output.
- updateQueue: UpdateQueue<any> | null,
- memoizedState: any,
- mode: TypeOfMode,
- effectTag: TypeOfSideEffect,
- nextEffect: Fiber | null,
- firstEffect: Fiber | null,
- lastEffect: Fiber | null,
- expirationTime: ExpirationTime,
- alternate: Fiber | null,
- // 时间
- actualDuration?: number,
- actualStartTime?: number,
- selfBaseTime?: number,
- treeBaseTime?: number,
- // 调试
- _debugID?: number,
- _debugSource?: Source | null,
- _debugOwner?: Fiber | null,
- _debugIsCurrentlyTiming?: boolean,
- |};
复制代码
key,type
这两个属性都是用来表示组件的, 更新组件的时候先检查 key 是否有改变, 如果改变的话则直接摧毁重建; 不变的话则继续检查 type 是否改变, 改变则直接摧毁重建; 否则重用原来的组件, 只是改变组件的属性. type 可能是用户定义的函数型或者类型的组合型组件, 或者是代表平台元素的字符串(如'div').
pendingProps,memoizedProps
概念上来说, props 就是一个函数的参数数组. pendingProps 是 Fiber 开始执行的时候被设定的, memoizedProps 在执行完之后. 每次更新的时候先比较 pendingProps 和 memoizedProps, 如果它们相同, 则表示先前的输出可以重用, 而不必进行多余的工作.
pendingWorkPriority
一个表面工作优先权的属性. 除 NoWork(它的值为 0)以外, 数值越大代表有限权越低.
- function matchesPriority(fiber, priority) {
- return fiber.pendingWorkPriority !== 0 &&
- fiber.pendingWorkPriority <= priority
- }
复制代码
参考文献
- React Fiber Architecture https://github.com/acdlite/react-fiber-architecture
- Codebase Overview https://reactjs.org/docs/codebase-overview.html
- Design Principles https://reactjs.org/docs/design-principles.html
来源: https://juejin.im/post/5b4dc19ee51d45190c18b3c8