Appearance
整体思路
在一个函数式组件中其只存在一个 FiberNode (workInProgress) , 然后在函数组件初次渲染的时候 声明了多少了 hook,就会存在hook
栗子
js
const App = props => {
// 添加一个 hook
const [visible, setVisible] = React.useState(true)
// 添加一个 hook
const [num, setNum] = React.useState(1)
const handleClickBtn = () => {
// setVisible hook上添加一个 update
setVisible(!visible)
}
// setNum hook上添加一个 update
setNum(num + 1)
// setNum hook上添加一个 update
setNum(num + 1)
return (
<div>
<button onClick={handleClickBtn}>切换</button>
</div>
)
}
所以在函数式组件初次渲染的时候 其所有的Hook的声明已经完成,并按照单项链表的顺序添加到 workInProgress.memoizedState
依赖的变量
需要注意的是 Hooks 的渲染流程是在 beginWork 中
workInProgressHook
跟workInProgress一样 是一个指向当前实例对象的属性
这边指向的是当前 workInProgress 的 hook
js/** * beginWork 初次渲染的时候 有一个Hooks就生成一个 hook对象,然后按照链表的结构保存到 workInProgreee.memoizedState上 * 然后再将workInProgressHook指向当前的 hook对象 * @returns */ function mountWorkInProgressHook(): Hook { const hook: Hook = { memoizedState: null, baseState: null, baseQueue: null, queue: null, next: null, }; // 如果当前函数组件第一次初始化 Hooks if (workInProgressHook === null) { // This is the first hook in the list currentlyRenderingFiber.memoizedState = workInProgressHook = hook; } else { // Append to the end of the list workInProgressHook = workInProgressHook.next = hook; } return workInProgressHook; } // 在Component执行完成后 /** * render函数式组件 * @param {*} current * @param {*} workInProgress * @param {*} Component * @param {*} props * @param {*} secondArg * @param {*} nextRenderLanes * @returns */ export function renderWithHooks<Props, SecondArg>( current: Fiber | null, workInProgress: Fiber, Component: (p: Props, arg: SecondArg) => any, props: Props, secondArg: SecondArg, nextRenderLanes: Lanes, ): any { renderLanes = nextRenderLanes; currentlyRenderingFiber = workInProgress; workInProgress.memoizedState = null; workInProgress.updateQueue = null; workInProgress.lanes = NoLanes; // 通过全局变量的方式缓存当前Hooks方法函数 // -- 初次渲染的时候 使用的是hook的 mountState 等方法 // -- 更新 的时候 使用的是hooks的 updateState 等方法 ReactCurrentDispatcher.current = current === null || current.memoizedState === null ? HooksDispatcherOnMount : HooksDispatcherOnUpdate; // 执行函数式组件 let children = Component(props, secondArg); // Check if there was a render phase update if (didScheduleRenderPhaseUpdateDuringThisPass) { let numberOfReRenders: number = 0; do { didScheduleRenderPhaseUpdateDuringThisPass = false; numberOfReRenders += 1; if (__DEV__) { // Even when hot reloading, allow dependencies to stabilize // after first render to prevent infinite render phase updates. ignorePreviousDependencies = false; } // Start over from the beginning of the list currentHook = null; workInProgressHook = null; workInProgress.updateQueue = null; ReactCurrentDispatcher.current = __DEV__ ? HooksDispatcherOnRerenderInDEV : HooksDispatcherOnRerender; children = Component(props, secondArg); } while (didScheduleRenderPhaseUpdateDuringThisPass); } ReactCurrentDispatcher.current = ContextOnlyDispatcher; const didRenderTooFewHooks = currentHook !== null && currentHook.next !== null; renderLanes = NoLanes; currentlyRenderingFiber = (null: any); currentHook = null; workInProgressHook = null; didScheduleRenderPhaseUpdate = false; return children; }
ReactCurrentDispatcher.current
js// 通过全局变量的方式缓存当前Hooks方法函数 // -- 初次渲染的时候 使用的是hook的 mountState 等方法 // -- 更新 的时候 使用的是hooks的 updateState 等方法 ReactCurrentDispatcher.current = current === null || current.memoizedState === null ? HooksDispatcherOnMount : HooksDispatcherOnUpdate;
保存了在初次渲染 或者 更新 提供不同的执行方法