在前面已经实现了Update
的基本架构,接下来的工作包括:
- 实现
mount
时调用的API - 将该API接入上述
Update
更新机制中
目前需要考虑的事情:
- 更新可能发生于任意组件,而更新流程是从根节点递归的
- 需要一个统一的根节点保存通用信息
ReactDOM.createRoot(rootElement).render()
IT社区对应到源码内部,执行ReactDOM.createRoot
会生成一个fiberRootNode
,然后传进来的rootElement
这个DOM也有对应的节点即hostRootFiber
,执行render方法,传进去App
组件,就挂载到hostRootFiber
上
container
保存对应宿主环境挂载的节点,暂时定义一个描述宿主环境对应方法的文件hostConfig.ts
react-reconciler/src/hostConfig.ts
exporttypeContainer=any;
https://www.swvq.comreact-reconciler/src/fiber.ts
fiberRootNode的current
指针指向hostRootFiber
finishiedWork指向已经更新完成的整个hostRootFiber
exportclassFiberRootNode{container:Container;current:FiberNode;finishedWork:FiberNode|null;constructor(container:Container,hostRootFiber:FiberNode){this.container=container;this.current=hostRootFiber;hostRootFiber.stateNode=this;this.finishedWork=null;}}
实现mount时调用的api**新建react-reconciler/src/fiberReconciler.ts
**对外暴露两个函数分别是:createContainer
、updateContainer
exportfunctioncreateContainer(container:Container){}exportfunctionupdateContainer(container:Container){}
实现createContainer
这个方法可以初始化一个hostRootFiber
和FiberRootNode
,并且调用createUpdateQueue
就能够实现fiberNode
与更新机制的关联
exportfunctioncreateContainer(container:Container){consthostRootFiber=newFiberNode(HostRoot,{},null);constroot=newFiberRootNode(container,hostRootFiber);hostRootFiber.updateQueue=createUpdateQueue();returnroot;}
来源于实现updateContainer
createUpdate
传入element就表明更新与这个element
相关,之后的更新就会对这个element
进行
exportfunctionupdateContainer(element:ReactElementType|null,root:FiberRootNode){consthostRootFiber=root.current;constupdate=createUpdate(element);enqueueUpdate(hostRootFiber.updateQueueasUpdateQueue,update);scheduleUpdateOnFiber(hostRootFiber);returnelement;}
完整代码
import{Container}from'hostConfig';import{ReactElementType}from'shared/ReactTypes';import{FiberNode,FiberRootNode}from'./fiber';import{createUpdate,createUpdateQueue,enqueueUpdate,UpdateQueue}from'./updateQueue';import{scheduleUpdateOnFiber}from'./workLoop';import{HostRoot}from'./workTags';exportfunctioncreateContainer(container:Container){consthostRootFiber=newFiberNode(HostRoot,{},null);constroot=newFiberRootNode(container,hostRootFiber);hostRootFiber.updateQueue=createUpdateQueue();returnroot;}exportfunctionupdateContainer(element:ReactElementType|null,root:FiberRootNode){consthostRootFiber=root.current;constupdate=createUpdate(element);enqueueUpdate(hostRootFiber.updateQueueasUpdateQueue,update);scheduleUpdateOnFiber(hostRootFiber);returnelement;}
如何让updateContainer与renderRoot更新流程串联上在workLoop
中实现scheduleUpdateOnFiber
,即在fiber中调度update
exportfunctionscheduleUpdateOnFiber(fiber:FiberNode){//TODO调度功能//fiberRootNodeconstroot=markUpdateFromFiberToRoot(fiber);renderRoot(root);}
从当前节点遍历到root节点
//从当前节点一直遍历到根节点functionmarkUpdateFromFiberToRoot(fiber:FiberNode){letnode=fiber;letparent=node.return;//普通的fiberNodewhile(parent!==null){node=parent;parent=node.return;}//hostRootFiber的时候if(node.tag===HostRoot){returnnode.stateNode;}returnnull;}
实现createWorkInProgress
exportconstcreateWorkInProgress=(current:FiberNode,pendingProps:Props):FiberNode=>{letwip=current.alternate;//首屏渲染wip===nullif(wip===null){//mountwip=newFiberNode(current.tag,pendingProps,current.key);wip.stateNode=current.stateNode;wip.alternate=current;current.alternate=wip;}else{//updatewip.pendingProps=pendingProps;//副作用清除掉可能是上次遗留的wip.flags=NoFlags;}wip.type=current.type;wip.updateQueue=current.updateQueue;wip.child=current.child;wip.memoizedProps=current.memoizedProps;wip.memoizedState=current.memoizedState;returnwip;};
整体流程createContainer
创建应用的根节点fiberRootNode
,并将fiberRootNode
与hostRootFiber
连接起来updateContainer
创建update
并将update
添加入updateQueue
中,将首屏渲染与触发更新的机制连接了起来
createUpdate
更新对应的数据结构update
createUpdateQueue
保存update的结构updateQueue
equeueUpdate
将update插入到updatequeue中processUpdateQueue
基于一个基础的状态以及pendingUpdate消费update,经过计算得到最终的状态memoizedState
当将update
插入到updatequeue
中之后执行scheduleUpdateOnFiber
开始调度流程
scheduleUpdateOnFiber
从当前节点一直遍历到fiberRootNode
,接着执行renderRootrenderRoot
首先根据fiberRootNode
的current生成workInProgressFiber
接着开始更新流程