react中的fiber和初次渲染

源码中定义了不同类型节点的枚举值

组件类型

  • 文本节点
  • HTML标签节点
  • 函数组件
  • 类组件
  • 等等

src/react/packages/react-reconciler/src/ReactWorkTags.js

javascript 复制代码
export const FunctionComponent = 0;
export const ClassComponent = 1;
export const IndeterminateComponent = 2; // Before we know whether it is function or class
export const HostRoot = 3; // Root of a host tree. Could be nested inside another node.
export const HostPortal = 4; // A subtree. Could be an entry point to a different renderer.
export const HostComponent = 5;
export const HostText = 6;
export const Fragment = 7;
export const Mode = 8;
export const ContextConsumer = 9;
export const ContextProvider = 10;
export const ForwardRef = 11;
export const Profiler = 12;
export const SuspenseComponent = 13;
export const MemoComponent = 14;
export const SimpleMemoComponent = 15;
export const LazyComponent = 16;
export const IncompleteClassComponent = 17;
export const DehydratedFragment = 18;
export const SuspenseListComponent = 19;
export const ScopeComponent = 21;
export const OffscreenComponent = 22;
export const LegacyHiddenComponent = 23;
export const CacheComponent = 24;

什么是fiber

A Fiber is work on a Component that needs to be done or was done. There can be more than one per component.

fiber是指组件上将要完成或者已经完成的任务,每个组件可以一个或者多个。

fiber结构

为什么需要fiber

  1. 为什么需要fiber

    对于大型项目,组件树会很大,这个时候递归遍历的成本就会很高,会造成主线程被持续占用,结果就是主线程上的布局、动画等周期性任务就无法立即得到处理,造成视觉上的卡顿,影响用户体验。

  2. 任务分解的意义

    解决上面的问题

  3. 增量渲染(把渲染任务拆分成块,匀到多帧)

  4. 更新时能够暂停,终止,复用渲染任务

  5. 给不同类型的更新赋予优先级

  6. 并发方面新的基础能力

  7. 更流畅

创建fiber结构

fiber就是一个js对象来抽象vnode

javascript 复制代码
function createFiber(vnode, returnFiber) {
  const fiber = {
    type: vnode.type,
    key: vnode.key,
    stateNode: null, // 原生标签时候指dom节点,类组件时候指的是实例
    props: vnode.props,
    child: null, // 第一个子fiber
    sibling: null, // 下一个兄弟fiber
    return: returnFiber, // 父节点
    // 标记节点是什么类型的
    flags: Placement,
    deletions: null, // 要删除子节点 null或者[]
    index: null, //当前层级下的下标,从0开始
    // 记录上一次的状态 函数组件和类组件不一样
    memorizedState: null,
    // old fiber
    alternate: null,
  };
  const { type } = vnode;

  if (isStr(type)) {
    // 原生标签
    fiber.tag = HostComponent;
  } else if (isFn(type)) {
    // 函数组件或者是类组件
    fiber.tag = type.prototype.isComponent ? ClassComponent : FunctionComponent;
  } else if (isUndefined(type)) {
    fiber.tag = HostText;
    fiber.props = { children: vnode };
  } else {
    fiber.tag = Fragment;
  }

  return fiber;
}

深度优先遍历每个fiber

对不同的类型节点tag,都有对应的处理方法

javascript 复制代码
function performUnitOfWork() {
  const { tag } = wip;

  switch (tag) {
    // 原生标签 比如div span button p a
    case HostComponent:
      updateHostComponent(wip);
      break;
    case FunctionComponent:
      updateFunctionComponent(wip);
      break;
    case ClassComponent:
      updateClassComponent(wip);
      break;
    case Fragment:
      updateFragmentComponent(wip);
      break;
    case HostText:
      updateHostTextComponent(wip);
      break;
    default:
      break;
  }

  if (wip.child) {
    wip = wip.child;
    return;
  }
  let next = wip;
  while (next) {
    if (next.sibling) {
      wip = next.sibling;
      return;
    }
    next = next.return;
  }
  wip = null;
}

初次渲染

在react项目中我们都是通过以下方法来初始化组件

javascript 复制代码
ReactDOM.createRoot(document.getElementById("root")).render(jsx);

那我们就来实现一下该createRoot和render方法

源码中的render是挂载到了原型对象上

javascript 复制代码
// react-dom
import createFiber from "./ReactFiber";
import { scheduleUpdateOnFiber } from "./ReactFiberWorkLoop";

// 构造函数
function ReactDOMRoot(internalRoot) {
  this._internalRoot = internalRoot;
}

ReactDOMRoot.prototype.render = function (children) {
  // 最原始的vnode节点(jsx) 我们需要的是fiber结构的vnode
  const root = this._internalRoot;
  // 原生dom节点
  console.log(root, "root");
  updateContainer(children, root);
};

// 初次渲染 组件到g根dom节点上
function updateContainer(element, container) {
  const { containerInfo } = container;
  const fiber = createFiber(element, {
    type: containerInfo.nodeName.toLocaleLowerCase(),
    stateNode: containerInfo,
  });
  // 组件初次渲染
  scheduleUpdateOnFiber(fiber);
}
function createRoot(container) {
  const root = { containerInfo: container };
  return new ReactDOMRoot(root);
}

// 一整个文件是ReactDOM, createRoot是ReactDOM上的一个方法
export default { createRoot };

后面湖会继续补充react是如何完成后续的渲染流程的 scheduleUpdateOnFiber方法

相关推荐
程序员与背包客_CoderZ3 分钟前
Node.js异步编程——Callback回调函数实现
前端·javascript·node.js·web
非凡ghost18 分钟前
Pale Moon:速度优化的Firefox定制浏览器
前端·firefox
清灵xmf33 分钟前
从 Set、Map 到 WeakSet、WeakMap 的进阶之旅
前端·javascript·set·map·weakset·weakmap
11054654011 小时前
11、参数化三维产品设计组件 - /设计与仿真组件/parametric-3d-product-design
前端·3d
爱笑的林羽1 小时前
Mac M系列 安装 jadx-gui
前端·macos
运维@小兵1 小时前
vue使用路由技术实现登录成功后跳转到首页
前端·javascript·vue.js
肠胃炎1 小时前
React构建组件
前端·javascript·react.js
邝邝邝邝丹1 小时前
React学习———React.memo、useMemo和useCallback
javascript·学习·react.js
酷爱码1 小时前
HTML5表格语法格式详解
前端·html·html5
hello_ejb31 小时前
聊聊JetCache的缓存构建
java·前端·缓存