本节我们讲解Hooks
的数据结构,为后面介绍具体的hook
打下基础。
在上一节的极简useState
实现中,使用isMount
变量区分mount
与update
。
在真实的Hooks
中,组件mount
时的hook
与update
时的hook
来源于不同的对象,这类对象在源码中被称为dispatcher
。
可见,mount
时调用的hook
和update
时调用的hook
其实是两个不同的函数。
在FunctionComponent
render
前,会根据FunctionComponent
对应fiber
的以下条件区分mount
与update
。
current === null || current.memoizedState === null
并将不同情况对应的dispatcher
赋值给全局变量ReactCurrentDispatcher
的current
属性。
在FunctionComponent
render
时,会从ReactCurrentDispatcher.current
(即当前dispatcher
)中寻找需要的hook
。
当错误的书写了嵌套形式的hook
,如:
useEffect(() => {
useState(0);
})
此时ReactCurrentDispatcher.current
已经指向ContextOnlyDispatcher
,所以调用useState
实际会调用throwInvalidHookError
,直接抛出异常。
接下来我们学习hook
的数据结构。
memoizedState: null,
baseState: null,
baseQueue: null,
queue: null,
next: null,
其中除memoizedState
以外字段的意义与上一章介绍的类似。
注意
fiber.memoizedState
:FunctionComponent
对应fiber
保存的链表。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
的创建过程。effect
链表同时会保存在fiber.updateQueue
中useRef:对于
useRef(1)
,memoizedState
保存{current: 1}
useMemo:对于
useMemo(callback, [depA])
,memoizedState
保存[callback(), depA]
有些是没有memoizedState
的,比如:
- useContext