0%

hook原理

hook就是解决函数组件没有state,生命周期,逻辑不能复用的一种解决方案

dispatcher

在真实hook中,组件mount时的hook和update时的hook来源于不同对象,这类对象在源码中称为dispatcher

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
// mount时的Dispatcher
const HooksDispatcherOnMount: Dispatcher = {
useCallback: mountCallback,
useContext: readContext,
useEffect: mountEffect,
useImperativeHandle: mountImperativeHandle,
useLayoutEffect: mountLayoutEffect,
useMemo: mountMemo,
useReducer: mountReducer,
useRef: mountRef,
useState: mountState,
// ...省略
};

// update时的Dispatcher
const HooksDispatcherOnUpdate: Dispatcher = {
useCallback: updateCallback,
useContext: readContext,
useEffect: updateEffect,
useImperativeHandle: updateImperativeHandle,
useLayoutEffect: updateLayoutEffect,
useMemo: updateMemo,
useReducer: updateReducer,
useRef: updateRef,
useState: updateState,
// ...省略
};

可见,mount时调用的hook和update时调用的hook是两个不同的函数,在FunctionComponent render前,会根据FunctionComponent对应fiber的一下条件区分mount和update

1
current === null || current.memoizedState === null

并把不同情况对应的dispatcher赋值给全局变量ReactCurrentDispatcher的current属性

1
2
ReactCurrentDispatcher.current =
current === null || current.memoizedState === null ? HookDispatcherOnMount : HooksDispatcherOnUpdate

在FuntionComponent render时,会从ReactCurrentDispatcher.current(即当前dispatcher,则FunctionComponent render时调用的hook是不同函数)

Hook数据结构:

1
2
3
4
5
6
7
const hook: Hook = {
memoizedState: null,
baseState: null,
baseQueue: null,
queue: null,
next: null
}

memoizedState:

hook与FunctionComponent fiber都存在memoizedState属性:

fiber.memoizedState:FunctionComponent对应fiber保存的Hooks链表

hook.memoizedState:Hooks链表中保存的单一hook对应的数据

不同类型hook的memoizedState保存不同类型数据:

useState:对于const [state,updateState] = useState(initialState),memoizedState保存state的值

useReducer:对于const[state,dispatch]=useReducer(reducer,[]),memoizedState保存state的值

useEffect:memoizedState保存包含useEffect回调函数,依赖项等的链表数据结构effect,effect会保存在fiber.updateQueue

useRef:对于useRef(1),memoizedState保存{current:1}

useMemo:对于useMemo(callback,[depA]),memoizedState保存[callback,depA],与useMemo的区别是,useCallback保存的是callback函数本身,而useMemo保存的是callback函数的执行结果

有些hook没有memoizedState:

如useContext