序
前面我们已经实现了Reconciler的架构,并且实现了renderRoot,renderRoot会执行更新的过程,所以我们推测调用renderRoot的是那些触发更新的API,那么在React中常见的触发更新的API如下:
- 对于首屏渲染来说是
ReactDOM.createRoot(),老版本的是ReactDOM.render - 对于类组件是
this.setState - 对于函数组件是
useState的dispatch方法
明确目标
目前我们希望实现一套统一的更新机制,即兼容上述触发更新的方式,并且方便后续扩展,从当前的同步更新变成后续的并发更新,因为React18是并发更新。
这种更新机制的组成部分
Update代表更新的数据结构UpdateQueue消费update的数据结构
从图中可以看到,一个UpdateQueue中有一个shared.pending,它指向update,如果我们有一个初始的状态,再消费这个update就得到了一个新的状态
实现Update基础结构
新建packages/react-reconciler/src/updateQueue.ts
实现Update接口
其中action需要兼容可能是function或新的值,即对应的this.setState({})|this.setState(()=>xxx)
export interface Update<State>{
action:Action<State>
}
// ReactTypes.ts
export type Action<State> = State | ((prevState: State)=>State)
实现创建Update的方法createUpdate返回一个Update的实例
export const createUpdate = <State>(action: Action<State>) => {
return {
action
};
};
实现UpdateQueue接口
export interface UpdateQueue<State> {
shared: {
pending: Update<State> | null;
};
}
实现创建UpdateQueue的方法createUpdateQueue
export const createUpdateQueue = <Action>() => {
return {
shared: {
pending: null
}
} as UpdateQueue<Action>;
};
实现往UpdateQueue中增加Update的方法enqueueUpdate
// 往updateQueue中添加update
export const enqueueUpdate = <Action>(
updateQueue: UpdateQueue<Action>,
update: Update<Action>
) => {
updateQueue.shared.pending = update;
};
实现UpdateQueue消费Update的方法processUpdateQueue
接受一个初始的状态以及我们需要消费的update,返回值是一个全新的状态,首先使用初始状态来初始化返回值,之后判断action是传入的全新的值还是函数,在进行赋值
export const processUpdateQueue = <State>(
baseState: State,
pendingUpdate: Update<State> | null
): { memoizedState: State } => {
const result: ReturnType<typeof processUpdateQueue<State>> = {
memoizedState: baseState
};
if (pendingUpdate !== null) {
// baseState 1 update 2 -> memoizedState 2
// baseState 1 update (x)=>4x -> memoizedState 4
const action = pendingUpdate.action;
if (action instanceof Function) {
result.memoizedState = action(baseState);
} else {
result.memoizedState = action;
}
}
return result;
};