实现更新机制
代码位置packages/react-reconciler/src/ReactFiberClassUpdateQueue.ts
创建update
react中触发更新的操作有一下几点
ReactDOM.createRoot(document.getElementById('root'))创建根节点也是更新操作的一环setStateuseState在源码中update是一个包含callback属性的对象,callback是一个触发更新的属性,接收用户传入的state或者函数。这里使用action代替
export type Action<State> = State | ((prevState: State) => State);
export interface Update<State> {
action: Action<State>;
}
export const createUpdate = <State>(action: Action<State>): Update<State> => {
return {
action,
};
};
创建updateQueue
react中每个react element对应的fiberNode中都有一个updateQueue用来管理update,updateQueue结构如下
export interface UpdateQueue<State> {
shared: {
pending: Update<State> | null;
};
}
export const createUpdateQueue = <State>() => {
return {
shared: {
pending: null,
},
} as UpdateQueue<State>;
};
update放入updateQueue中
主要实现把update赋值给updateQueue.shared.pending
export const enqueueUpdate = <State>(
updateQueue: UpdateQueue<State>,
update: Update<State>,
) => {
updateQueue.shared.pending = update;
};
执行update
processUpdateQueue来执行update,实现更新
export const processUpdateQueue = <State>(
baseState: State,
pendingState: Update<State> | null,
): {
memoizedState: State;
} => {
const result: ReturnType<typeof processUpdateQueue<State>> = {
memoizedState: baseState,
};
if (pendingState) {
const action = pendingState.action;
if (action instanceof Function) {
result.memoizedState = action(baseState);
} else {
result.memoizedState = action;
}
}
return result;
};
接入更新机制
packages/react-reconciler/src/ReactFiberReconciler.ts 在update更新机制创建完成之后需要把update机制接入,react的更新是从根节点开始的,由上而下的进行的。
根节点的fiberNode需要另一个fiber节点指向它,这个最顶点的节点叫fiberRootNode
- 顶节点:fiberRootNode
- 根节点fiberNode: hostRootFiber
createContainer-创建获取fiberRootNode的方法
// FiberRootNode
// packages/react-reconciler/src/ReactFiber.ts
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;
}
}
// // packages/react-reconciler/src/ReactFiberReconciler.ts
export const createContainer = (container: Container) => {
const hostRootFiber = new FiberNode(HostRoot, {}, null);
const root = new FiberRootNode(container, hostRootFiber);
hostRootFiber.updateQueue = createUpdateQueue(); // fiberNode 添加updateQueue
return root;
};
updateContainer - 创建容器时执行更新
// packages/react-reconciler/src/ReactFiberReconciler.ts
export const updateContainer = (
element: ReactElement | null,
root: FiberRootNode,
) => {
const hostRootFiber = root.current;
const update = createUpdate<ReactElement | null>(element);
// 添加update
enqueueUpdate(
hostRootFiber.updateQueue as UpdateQueue<ReactElement | null>,
update,
);
scheduleUpdateOnFiber(hostRootFiber); // 调度更新
return element;
};
scheduleUpdateOnFiber调度更新
// packages/react-reconciler/src/ReactFiberWorkLoop.ts
export function scheduleUpdateOnFiber(fiberNode: FiberNode) {
const root = markUpdateFromFiberToRoot(fiberNode);
renderRoot(root);
}
markUpdateFromFiberToRoot 通过fiberNode寻找fiberRootNode
// // packages/react-reconciler/src/ReactFiberWorkLoop.ts
function markUpdateFromFiberToRoot(fiberNode: FiberNode) {
let node = fiberNode;
let parent = node.return;
while (parent !== null) {
node = parent;
parent = node.return;
}
// 当前是hostRootFiber
if (node.tag == HostRoot) {
return node.stateNode;
}
return null;
}
renderRoot循环遍历fiberNode
function renderRoot(root: FiberRootNode) {
prepareFreshStack(root);
do {
try {
workLoop();
} catch (e) {
console.warn('workLoop出错', e);
workInProgressRoot = null;
}
} while (true);
}
function prepareFreshStack(root: FiberRootNode) {
// root.current->hostRootFiber
workInProgressRoot = createWorkInProgress(root.current, {});
}
createWorkInProgress 获取workInProgress
createWorkInProgress中可以确定当前是挂载还是更新
export const createWorkInProgress = (
current: FiberNode,
pendingProps: Props,
): FiberNode => {
let wip = current.alternate;
if (wip === null) {
// mount
wip = new FiberNode(current.tag, pendingProps, current.key);
wip.type = current.type;
wip.stateNode = current.stateNode;
wip.alternate = current;
current.alternate = wip;
} else {
// update
wip.pendingProps = pendingProps;
wip.flags = NoFlags; // 初始化所有副作用
}
// 复用current中的部分属性
wip.type = current.type;
wip.updateQueue = current.updateQueue;
wip.child = current.child;
wip.memoizedState = current.memoizedState;
return wip;
};