Appearance
FunctionComponent 组件
函数式组件类型
renderWithHooks
主要是生成首次 mount 和 update 的时候 hooks 的函数方法,从而保证在首次执行的时候可以生成对应的值,在更新的时候可以根据条件去判断是否需要更新
- 通过全局变量的方式缓存当前 Hooks 方法函数
- 初次渲染的时候 使用的是 hook 的 mountState 等方法
- 更新 的时候 使用的是 hooks 的 updateState 等方法
js
ReactCurrentDispatcher.current =
current === null || current.memoizedState === null
? HooksDispatcherOnMount
: HooksDispatcherOnUpdate;- 执行函数式组件
js
let children = Component(props, secondArg);- 检查组件渲染期间可能发生的状态更新。
如果为 true ,则表示在组件的渲染阶段发生了状态更新(setState),需要重新渲染组件。 如在函数组件体内部直接调用了 setState。这种情况会导致 React 需要重新渲染组件,以确保状态更新被正确处理。为了防止无限循环,React 会限制重新渲染的次数,最多 25 次,超过就会抛出错误
如何实现
在 hooks 执行的时候,即 dispathAction 的方法中会将全局的 didScheduleRenderPhaseUpdate 设置为 true,从而表示在组件的渲染阶段发生了状态更新。
js
function dispatchAction<A>(
componentIdentity: Object,
queue: UpdateQueue<A>,
action: A
) {
if (componentIdentity === currentlyRenderingComponent) {
// This is a render phase update. Stash it in a lazily-created map of
// queue -> linked list of updates. After this render pass, we'll restart
// and apply the stashed updates on top of the work-in-progress hook.
didScheduleRenderPhaseUpdate = true;
}
}那么如果在渲染阶段发生了状态更新,那么就可以通过 didScheduleRenderPhaseUpdateDuringThisPass 来判断是否需要重新渲染组件。
js
if (didScheduleRenderPhaseUpdateDuringThisPass) {
// Keep rendering in a loop for as long as render phase updates continue to
// be scheduled. Use a counter to prevent infinite loops.
let numberOfReRenders: number = 0;
do {
didScheduleRenderPhaseUpdateDuringThisPass = false;
localIdCounter = 0;
if (numberOfReRenders >= RE_RENDER_LIMIT) {
throw new Error(
"Too many re-renders. React limits the number of renders to prevent " +
"an infinite loop."
);
}
numberOfReRenders += 1;
// 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);
}- 重置全局的 hooks 函数方法,防止在非函数式组件中调用了 hooks 方法
js
// 重置 hooks 函数 ,防止其他地方调用 hooks 方法,被污染
ReactCurrentDispatcher.current = ContextOnlyDispatcher;reconcileChildren
- mountChildFibers | reconcileChildFibers
这两个方法的核心都是调用 reconcileChildFibers 方法,只是在 mount 阶段的时候 ,会将 shoudTrackEffects 设置为 true,从而在 reconcileChildFibers 方法中会将新的 FiberNode 节点添加到 workInProgress 的 child 链表中。
js
export const reconcileChildFibers = ChildReconciler(true);
export const mountChildFibers = ChildReconciler(false);