React Hooks 可以说完全颠覆了之前 Class Component 的写法,进一步增强了状态复用的能力,让 Function Component 也具有了内部状态,对于我个人来说,更加喜欢 Hooks 的写法。当然如果你是一个使用 Class Component 的老手,初期上手时会觉得很苦恼,毕竟之前沉淀的很多 HOC、Render Props 组件基本没法用。而且之前的 Function Component 是无副作用的无状态组件,现在又能通过 Hooks 引入状态,看起来真的很让人疑惑。Function Component 的另一个优势就是可以完全告别 this ,在 Class Component 里面 this 真的是一个让人讨厌的东西?? 。
Hook 如何与组件关联
在之前的文章中多次提到,Fiber 架构下的 updateQueue、effectList 都是链表的数据结构,然后挂载的 Fiber 节点上。而一个函数组件内所有的 Hooks 也是通过链表的形式存储的,最后挂载到 fiber.memoizedState 上。
- function App() {
- const [num, updateNum] = useState(0)
- return <div
- onClick={() => updateNum(num => num + 1)}
- >{ num }</div>
- }
- export default App
我们先简单看下,调用 useState 时,构造链表的过程:
- var workInProgressHook = null
- var HooksDispatcherOnMount = {
- useState: function (initialState) {
- return mountState(initialState)
- }
- }
- function function mountState(initialState) {
- // 新的 Hook 节点
- var hook = mountWorkInProgressHook()
- // 缓存初始值
- hook.memoizedState = initialState
- // 构造更新队列,类似于 fiber.updateQueue
- var queue = hook.queue = {
- pending: null,
- dispatch: null,
- lastRenderedState: initialState
- }
- // 用于派发更新
- var dispatch = queue.dispatch = dispatchAction.bind(
- null, workInProgress, queue
- )
- // [num, updateNum] = useState(0)
- return [hook.memoizedState, dispatch]
- }
- function mountWorkInProgressHook() {
- var hook = {
- memoizedState: null,
- baseState: null,
- baseQueue: null,
- queue: null,
- next: null
- }
- if (workInProgressHook === null) {
- // 构造链表头节点
- workInProgress.memoizedState = workInProgressHook = hook
- } else {
- // 如果链表已经存在,在挂载到 next
- workInProgressHook = workInProgressHook.next = hook
- }
- return workInProgressHook
- }