序
在前面已经实现了Update的基本架构,接下来的工作包括:
- 实现
mount时调用的API - 将该API接入上述
Update更新机制中
目前需要考虑的事情:
- 更新可能发生于任意组件,而更新流程是从根节点递归的
- 需要一个统一的根节点保存通用信息
ReactDOM.createRoot(rootElement).render(<App/>)
对应到源码内部,执行ReactDOM.createRoot会生成一个fiberRootNode,然后传进来的rootElement这个DOM也有对应的节点即hostRootFiber,执行render方法,传进去App组件,就挂载到hostRootFiber上
实现fiberRootNode
container保存对应宿主环境挂载的节点,暂时定义一个描述宿主环境对应方法的文件hostConfig.ts
react-reconciler/src/hostConfig.ts
export type Container = any;
react-reconciler/src/fiber.ts
fiberRootNode的current指针指向hostRootFiber
finishiedWork指向已经更新完成的整个hostRootFiber
export class FiberRootNode {
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
export function createContainer(container:Container){}
export function updateContainer(container:Container){}
实现createContainer
这个方法可以初始化一个hostRootFiber和FiberRootNode,并且调用createUpdateQueue就能够实现fiberNode与更新机制的关联
export function createContainer(container: Container) {
const hostRootFiber = new FiberNode(HostRoot, {}, null);
const root = new FiberRootNode(container, hostRootFiber);
hostRootFiber.updateQueue = createUpdateQueue();
return root;
}
实现updateContainer
createUpdate传入element就表明更新与这个element相关,之后的更新就会对这个element进行
export function updateContainer(
element: ReactElementType | null,
root: FiberRootNode
) {
const hostRootFiber = root.current;
const update = createUpdate<ReactElementType | null>(element);
enqueueUpdate(
hostRootFiber.updateQueue as UpdateQueue<ReactElementType | null>,
update
);
scheduleUpdateOnFiber(hostRootFiber);
return element;
}
完整代码
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';
export function createContainer(container: Container) {
const hostRootFiber = new FiberNode(HostRoot, {}, null);
const root = new FiberRootNode(container, hostRootFiber);
hostRootFiber.updateQueue = createUpdateQueue();
return root;
}
export function updateContainer(
element: ReactElementType | null,
root: FiberRootNode
) {
const hostRootFiber = root.current;
const update = createUpdate<ReactElementType | null>(element);
enqueueUpdate(
hostRootFiber.updateQueue as UpdateQueue<ReactElementType | null>,
update
);
scheduleUpdateOnFiber(hostRootFiber);
return element;
}
如何让updateContainer与renderRoot更新流程串联上
在workLoop中实现scheduleUpdateOnFiber,即在fiber中调度update
export function scheduleUpdateOnFiber(fiber: FiberNode) {
// TODO 调度功能
// fiberRootNode
const root = markUpdateFromFiberToRoot(fiber);
renderRoot(root);
}
从当前节点遍历到root节点
// 从当前节点一直遍历到根节点
function markUpdateFromFiberToRoot(fiber: FiberNode) {
let node = fiber;
let parent = node.return;
// 普通的fiberNode
while (parent !== null) {
node = parent;
parent = node.return;
}
// hostRootFiber的时候
if (node.tag === HostRoot) {
return node.stateNode;
}
return null;
}
实现createWorkInProgress
export const createWorkInProgress = (
current: FiberNode,
pendingProps: Props
): FiberNode => {
let wip = current.alternate;
// 首屏渲染wip===null
if (wip === null) {
// mount
wip = new FiberNode(current.tag, pendingProps, current.key);
wip.stateNode = current.stateNode;
wip.alternate = current;
current.alternate = wip;
} else {
// update
wip.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;
return wip;
};
整体流程
createContainer创建应用的根节点fiberRootNode,并将fiberRootNode与hostRootFiber连接起来updateContainer创建update并将update添加入updateQueue中,将首屏渲染与触发更新的机制连接了起来
触发更新机制包含
createUpdate更新对应的数据结构updatecreateUpdateQueue保存update的结构updateQueueequeueUpdate将update插入到updatequeue中processUpdateQueue基于一个基础的状态以及pendingUpdate消费update,经过计算得到最终的状态memoizedState
fiberReconciler中
当将update插入到updatequeue中之后执行scheduleUpdateOnFiber开始调度流程
workLoop中
scheduleUpdateOnFiber从当前节点一直遍历到fiberRootNode,接着执行renderRootrenderRoot首先根据fiberRootNode的current生成workInProgressFiber接着开始更新流程