首次执行ReactDOM.render会创建fiberRootNode(源码中叫fiberRoot)和rootFiber。
fiberRootNode
fiberRootNode是整个应用的根节点,绑定在真实DOM节点的_reactRootContainer属性上,当对一个元素重复调用ReactDOM.render时fiberRootNode不会改变。
//FiberRoot
const rootFiber= new FiberNode();
const fiberRootNode={
current: rootFiber,
containerInfo: containerInfo,
context: null,
pendingContext: null,
expirationTime: NoWork,
.......
}
rootFiber.stateNode=fiberRootNode
rootFiber
rootFiber是<App/>所在组件树的根节点,rootFiber在每次重新渲染的时候会重新构建。
diff算法的作用对象也是rootFiber树和当前虚拟dom树。
// Instance
this.tag = 3; // 不同的组件类型
this.key = null; // react element 的 key
this.elementType = null; // react element 的 type
this.type = null; // 异步组件resolved之后返回的内容,一般是`function`或者`class`
this.stateNode = null; // 跟当前Fiber相关本地状态(比如浏览器环境就是DOM节点)
// Fiber
this.return = null; // 指向他在Fiber节点树中的`parent`,用来在处理完这个节点之后向上返回
this.child = null; // 指向自己的第一个子节点
this.sibling = null; // 兄弟节点的return指向同一个父节点
this.index = 0;
this.ref = null; // ref
this.pendingProps = pendingProps; // 新的 props
this.memoizedProps = null; // 旧的 props
this.memoizedState = null; // 新旧 state
this.updateQueue = null; // 该Fiber对应的组件产生的Update会存放在这个队列里面
this.dependencies = null;
this.mode = mode; // Effects 表示这个子树是否默认是异步渲染的
//effect
this.effectTag = NoEffect; // 用来记录Side Effect
this.nextEffect = null; // 用来快速查找下一个side effect
this.firstEffect = null; // 第一个side effect
this.lastEffect = null; // 最后一个side effect
this.alternate = null; // `current <==> workInProgress` 在渲染完成之后他们会交换位置,类似于备份,方便重用
为什么要区分
在应用中当多次调用ReactDOM.render渲染不同的组件树的时候,它们会拥有不同的rootFiber,但整个应用的根节点只有一个fiberRootNode。
fiberRootNode的current会指向当前页面上已渲染内容对应Fiber树,即current Fiber树。
fiberRootNode.current = rootFiber;