说实话,是个正常人都看不懂
let isMount = true;
//一个指针,指向当前的hook
let workInProgressHook=null;
const fiber = {
//保存的是这个函数本身
stateNode:App,
//保存对应的hooks的数据的
memoizedState:null
}
//每个useState都会,创建一个hook
//并且通过workInProgressHook.next
//串成一个链表
//有很多useState 那我们怎么知道当前useState对应的那个hook?
function useState(initialState) {
let hook;
if(isMount){
//他是一个链表,单向链表
hook={
//initalState 就是useState初始化的时候定义的值
memoizedState: initialState,
next:null,
//保存触发更新的函数
queue:{
pending:null
}
}
//考虑第一次渲染,第一个useState
if(!fiber.memoizedState){
fiber.memoizedState=hook;
}else{
//else考虑第一次渲染,后续的多个useState
//取得上一次的workInProgressHook他的next=当前hook
workInProgressHook.next=hook;
}
workInProgressHook=hook;
}else{
//在updata时
//(在这里需要解释一下hook和当前hook的区别么?)
//hook = workInProgressHook(理解为当前hook)
hook=workInProgressHook;
//当前hook=当前hook.next
//下一次再进来,就按顺序了
workInProgressHook=workInProgressHook.next;
}
//取到了 当前useState的数据,
//基于当前的数据做一些处理
let baseState = hook.memoizedState;
//代表需要更新
if(hook.queue.pending){
// hook.queue.pending是最后一个
//所以.next 是第一个
let firstUpdate = hook.queue.pending.next;
do{
const action = firstUpdate.action
baseState = action(baseState);
firstUpdate = firstUpdate.next;
//因为是环形链表,所以相同时说明遍历完了
} while(firstUpdate !== hook.queue.pending.next)
//每次更新完,滞空
hook.queue.pending = null;
}
hook.memoizedState = baseState;
return [baseState,dispatchAction.bind(null,hook.queue)]
}
//dispatchAction就是setState的函数
//我们怎么知道dispatchAction对应的那个useState呢?
function dispatchAction(queue,action) {
//创建一个更新
const update = {
action,
next:null
}
//每次更新完,都清空了,所以永远是null
if(queue.pending === null){
//自己指向自己,形成一个环形链表
update.next = update;
}else{
// u0->u0
//U1 -> U0 -> U1
update.next = queue.pending.next
queue.pending.next=update
}
//每次 都是当前的update
queue.pending = update;
schedule();
}
//调度 ,每次更新都会触发调度,组件就会重新runder
function schedule(){
//指针重新指向 链表的第一个
workInProgressHook=fiber.memoizedState
//首次调用
const app = fiber.stateNode();
isMount=false;
return app;
}
function App (){
const [num,updateNum] = useState(0);
return {
onClick(){
updateNum((num)=>num+1);
updateNum((num)=>num+2);
}
}
}
window.app = schedule();
app.onClick()