栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 软件开发 > 后端开发 > Java

React FiberRoot和RootFiber源码

Java 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

React FiberRoot和RootFiber源码

ReactDOM.render源码解析
上文提到fiberRoot和rootFiber, 它们到底是什么, 有什么关联?

两者的关系:

为什么要区分?

在应用中ReactDOM.render可以被多次调用, 它们可以拥有不同的rootFiber(FiberNode), 但是整个应用的根节点只能是一个, 那就是fiberRoot(fiberRootNode)

从上图可以看出fiberRoot(fiberRootNode)的current指向的是rootFiber(FiberNode), 也就是当前页面中所需要渲染的内容对应的Fiber树, 即 current fiber 树

FiberRoot(fiberRootNode)

它是整个应用的根节点, 绑定在container._reactRootContainer, 也就是绑定在真实DOM节点的_reactRootContainer属性上, 就算是重复调用ReactDOM.render, FiberRoot(fiberRootNode)还是不变的, 内部做了判断. 详情可以看源码(源码地址)

createFiberRoot 源码

源码地址

export function createFiberRoot(
  containerInfo: any,
  tag: RootTag,
  hydrate: boolean,
  hydrationCallbacks: null | SuspenseHydrationCallbacks,
): FiberRoot {
  // 创建fiberRoot(fiberRootNode)
  const root: FiberRoot = (new FiberRootNode(containerInfo, tag, hydrate): any);
  if (enableSuspenseCallback) {
    root.hydrationCallbacks = hydrationCallbacks;
  }

  // Cyclic construction. This cheats the type system right now because
  // stateNode is any.
  const uninitializedFiber = createHostRootFiber(tag);// 创建rootFiber(fiberNode)

  // 把rootFiber挂载到fiberRoot的current属性上  
  root.current = uninitializedFiber;

  // 把fiberRoot挂载到rootFiber的stateNode属性上
  uninitializedFiber.stateNode = root;

  // 初始化更新队列
  initializeUpdateQueue(uninitializedFiber);

  return root;
}

这一段代码, 可以很好的解释上面fiberRoot和rootFiber关系图

FiberRootNode 对象

源码地址

type BaseFiberRootProperties = {|
  // The type of root (legacy, batched, concurrent, etc.)

  
  tag: RootTag,

  // root节点, 也就是ReactDOM.render(, document.getElementById('root'))的第二个参数
  containerInfo: any,
  
  pendingChildren: any,
  
  //current:Fiber对象 对应的是 root 节点,即整个应用根对象
  current: Fiber,

  pingCache: WeakMap> | Map> | null,

  // A finished work-in-progress HostRoot that's ready to be committed.
  finishedWork: Fiber | null,
  // Timeout handle returned by setTimeout. Used to cancel a pending timeout, if
  // it's superseded by a new one.
  timeoutHandle: TimeoutHandle | NoTimeout,
  // Top context object, used by renderSubtreeIntoContainer
  context: Object | null,
  pendingContext: Object | null,
  // Determines if we should attempt to hydrate on the initial mount
  +hydrate: boolean,

  // Used by useMutableSource hook to avoid tearing during hydration.
  mutableSourceEagerHydrationData?: Array<
    MutableSource | MutableSourceVersion,
  > | null,

  // Node returned by Scheduler.scheduleCallback. Represents the next rendering
  // task that the root will work on.
  callbackNode: *,
  callbackPriority: LanePriority,
  eventTimes: LaneMap,
  expirationTimes: LaneMap,

  pendingLanes: Lanes,
  suspendedLanes: Lanes,
  pingedLanes: Lanes,
  expiredLanes: Lanes,
  mutableReadLanes: Lanes,

  finishedLanes: Lanes,

  entangledLanes: Lanes,
  entanglements: LaneMap,
|};

rootFiber(fiberNode)

rootFiber是所在组件树的根节点,rootFiber在每次重新渲染的时候会重新构建。
本身就是一个普通的fiberNode, 上面通过createHostRootFiber(tag)创建, 其实最终还是通过createFiber函数创建的.

export function createHostRootFiber(tag: RootTag): Fiber {
  ....
  return createFiber(HostRoot, null, null, mode);
}
const createFiber = function(
  tag: WorkTag,
  pendingProps: mixed,
  key: null | string,
  mode: TypeOfMode,
): Fiber {
  // $FlowFixMe: the shapes are exact here but Flow doesn't like constructors
  return new FiberNode(tag, pendingProps, key, mode);
};
FiberNode

源码地址

function FiberNode(
  tag: WorkTag,
  pendingProps: mixed,
  key: null | string,
  mode: TypeOfMode,
) {
  // Instance

	
   // tag 组件的类型 是函数组件, 类组件, Fragment, 原生的标签...
  this.tag = tag;
  
  this.key = key; 

  this.elementType = null;

  // 对于 函数组件,指函数本身,对于类组件,指class
  this.type = null;

  // Fiber对应的真实DOM节点
  this.stateNode = null; 

  // 以下属性用于连接其他Fiber节点形成Fiber树。

  // 指向父fiber节点
  this.return = null;
  
  // 指向第一个子fiber节点
  this.child = null;

  // 指向第一个兄弟fiber节点
  this.sibling = null;
  this.index = 0;

  // 真实的DOM属性
  this.ref = null;

  // 新传入的 props
  this.pendingProps = pendingProps;

  // 之前的 props
  this.memoizedProps = null;

  // 更新队列,用于暂存 setState 的值
  this.updateQueue = null;

  // 之前的 state
  this.memoizedState = null;
  this.dependencies = null;

  this.mode = mode;

  // 保存本次更新会造成的DOM操作。比如删除,移动
  this.flags = NoFlags;
  this.nextEffect = null;

  this.firstEffect = null;
  this.lastEffect = null;

  this.lanes = NoLanes;
  this.childLanes = NoLanes;


  //用于链接新树和旧树;旧->新,新->旧
  this.alternate = null;
}
stateNode和alternate属性

stateNode: Fiber对应的真实DOM节点

查看stateNode, 测试代码:

function App(props) {
  const content = 
; console.log(content); return content; } ReactDOM.render(, document.getElementById("root"));

alternate属性
第一个作用: 判断是首次渲染还是更新
第二个作用: 是当前更新的fiber tree(workInProgress tree) 和 current fiber tree(old tree)的桥梁

  • 该属性在节点初始化的时候默认为空(this.alternate = null)。这个节点的作用就是用来缓存之前的 Fiber 节点,更新的时候会判断 fiber.alternate 是否为空来确定当前是首次渲染还是更新.
  • react更新的时候其实存在两颗fiber树 [将产生update的React Element和current Fiber Tree(也就是old Tree)进行比较, 最终在内存中生成workInProgress tree], 我们使用alternate去连接old tree.

查看alternate, 测试代码:

function App(props) {
  const [a, setA] = React.useState("");
  const content = (
    
() => { setA(Math.random()); }} > haha{a}
); console.log(content); // 每次更新操作, 就打印出最新的fiber tree return content; } ReactDOM.render(, document.getElementById("root"));

转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/1020250.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号