useState, part 2: useState更新事件的触发
2021年4月19日 • ... • ☕️ 2 min read
之前看了useState实际做了dispatch回调的绑定:
dispatch = queue.dispatch = dispatchAction.bind(null, currentFiber, queue)
//...
return [hook.memoizedState, dispatch]
然后通过MemorizedState和Hooks连接起来:
Fiber Node和workInProgressHook的关联
这次看一下事件的触发。
比如调用一个set函数
const Foo = () => {
console.log('123');
const [data, setData] = useState('foo');
const clickHandler = () => {
setData('bar')
};
return (<div onClick={clickHandler}>{data}</div>);
};
事件触发部分这里不看,从事件触发的set方法开始。
流程
调用useState
第二个返回值的时候,会实际触发dispatchAction
函数。所以调用setXXX即调用dispatchAction
函数,所以这是整个useState的关键环节。
dispatchAction
这个函数bind了currentFiber
和queue
,所以调用的时候自带3个参数:
fiber
, queue
, action
其中action
可以是一个值,也可以是函数。
dispatchAction
-_lastRenderedReducer // 获取下一个state(由action获取),如果和当前state一致直接退出(这里会使用Object.is对比,相同则直接退出)
// 保存到一个update里,并把update放到更新队列queue里
update{
expirationTime: _expirationTime,
suspenseConfig: _suspenseConfig,
action: action,
eagerReducer:_lastRenderedReducer,
eagerState: _eagerState,
next: linked node
}
多个state存储
如果是多个state,怎么存储呢?
答案是Fiber节点的memoizedState
(即firstWorkInProgressHook
)里的next属性。
它其实作为一个链表的指针,指向下一个state节点,下一个节点上又能找到memoizedState和next。
这样,所有属于该Fiber的数据,就存储起来了。
只有节点上的memoizedState存储了一个对象,其他(next)都是直接存state内容。
后续更新过程
后面就是正常的触发一个更新过程,附带deadline时间片控制的,不是这里的重点,简单看一下:
scheduleUpdateOnFiber(fiber, expirationTime)
-scheduleCallbackForRoot
-Scheduler_scheduleCallback
queue=[runRootCallback]
performWorkUntilDeadline
-flushSyncCallbackQueue // flush前面的queue队列(依次执行)
函数主体是个循环
do{
callback = callback();
} while (callback !== null);
-runRootCallback
-renderRoot
这个函数return commitRoot
,即callback = commitRoot
,继续执行
-commitRoot
总结
整体看来,useState引入的状态变化方法,抛开整体的Fiber结构适配和deadline时间片控制优化,对整体的流程改变其实不大。但是hooks的设计思路(统一通过Dispatcher
调度),却能迁移到更多的地方。比如useEffect
和useCallback
// useEffect
-dispatcher = resolveDispatcher() // 返回当前dispatcher
dispatcher.useEffect(create, inputs)
-mountEffect(create, inputs)
// useCallback
dispatcher = resolveDispatcher() // 返回当前dispatcher
dispatcher.useCallback(callback, inputs)
-mountCallback(callback, deps)