9.hooks源码(想知道Function Component是怎样保存状态的嘛)
人人都能读懂的react源码解析(大厂高薪必备)
9.hooks源码(想知道Function Component是怎样保存状态的嘛)
视频课程&调试demos
视频课程的目的是为了快速掌握react源码运行的过程和react中的scheduler、reconciler、renderer、fiber等,并且详细debug源码和分析,过程更清晰。
课程结构:
hook调用入口
在hook源码中hook存在于Dispatcher中,Dispatcher就是一个对象,不同hook 调用的函数不一样,全局变量ReactCurrentDispatcher.current会根据是mount还是update赋值为HooksDispatcherOnMount或HooksDispatcherOnUpdate
ReactCurrentDispatcher.current =
current === null || current.memoizedState === null//mount or update
? HooksDispatcherOnMount
: HooksDispatcherOnUpdate;
const HooksDispatcherOnMount: Dispatcher = {//mount时
useCallback: mountCallback,
useContext: readContext,
useEffect: mountEffect,
useImperativeHandle: mountImperativeHandle,
useLayoutEffect: mountLayoutEffect,
useMemo: mountMemo,
useReducer: mountReducer,
useRef: mountRef,
useState: mountState,
//...
};
const HooksDispatcherOnUpdate: Dispatcher = {//update时
useCallback: updateCallback,
useContext: readContext,
useEffect: updateEffect,
useImperativeHandle: updateImperativeHandle,
useLayoutEffect: updateLayoutEffect,
useMemo: updateMemo,
useReducer: updateReducer,
useRef: updateRef,
useState: updateState,
//...
};
hook数据结构
在FunctionComponent中,多个hook会形成hook链表,保存在Fiber的memoizedState的上,而需要更新的Update保存在hook.queue.pending中
const hook: Hook = {
memoizedState: null,//对于不同hook,有不同的值
baseState: null,//初始state
baseQueue: null,//初始queue队列
queue: null,//需要更新的update
next: null,//下一个hook
};
下面来看下memoizedState对应的值
useState:例如,state的值
useReducer:例如,state的值
useEffect:在mountEffect时会调用pushEffect创建effect链表,就等于effect链表,effect链表也会挂载到fiber.updateQueue上,每个effect上存在useEffect的第一个参数回调和第二个参数依赖数组,例如,,effect就是{create:callback, dep:dep,…}
useRef:例如,memoizedState{current: 0}
useMemo:例如,等于
useCallback:例如,等于。保存函数,保存的执行结果
useState&useReducer
之所以把useState和useReducer放在一起,是因为在源码中useState就是有默认reducer参数的useReducer。
useState&useReducer声明
mount阶段
update阶段
执行阶段
useEffect
声明
mount阶段
update阶段
执行阶段
useRef
sring类型的ref已经不在推荐使用,ForwardRef只是把ref通过传参传下去,createRef也是{current: any这种结构,所以我们只讨论function或者{current: any}的useRef
//createRef返回{current: any}
export function createRef(): RefObject {
const refObject = {
current: null,
};
return refObject;
}
//ForwardRef第二个参数是ref对象
let children = Component(props, secondArg);
声明阶段
mount阶段
update阶段
useMemo&useCallback
声明阶段
mount阶段
update阶段
function updateMemo(
nextCreate: () => T,
deps: Array | void | null,
): T {
const hook = updateWorkInProgressHook();//获取hook
const nextDeps = deps === undefined ? null : deps;
const prevState = hook.memoizedState;
if (prevState !== null) {
if (nextDeps !== null) {
const prevDeps: Array | null = prevState[1];
if (areHookInputsEqual(nextDeps, prevDeps)) {//浅比较依赖
return prevState[0];//没变 返回之前的状态
}
}
}
const nextValue = nextCreate();//有变化重新调用callback
hook.memoizedState = [nextValue, nextDeps];
return nextValue;
}
function updateCallback(callback: T, deps: Array | void | null): T {
const hook = updateWorkInProgressHook();//获取hook
const nextDeps = deps === undefined ? null : deps;
const prevState = hook.memoizedState;
if (prevState !== null) {
if (nextDeps !== null) {
const prevDeps: Array | null = prevState[1];
if (areHookInputsEqual(nextDeps, prevDeps)) {//浅比较依赖
return prevState[0];//没变 返回之前的状态
}
}
}
hook.memoizedState = [callback, nextDeps];//变了重新将[callback, nextDeps]赋值给memoizedState
return callback;
}