# useLayoutEffect源码实现
# packages/react/src/ReactHooks.js
export function useLayoutEffect(create, deps) {
const dispatcher = resolveDispatcher();
return dispatcher.useLayoutEffect(create, deps);
# packages/react/src/React.js
import { useLayoutEffect } from './ReactHooks';
export {
useLayoutEffect
# packages/react/index.js
export {
useLayoutEffect
# packages/react-reconciler/src/ReactFiberHooks.js
import { Passive as PassiveEffect, Update as UpdateEffect } from './ReactFiberFlags';
import { HasEffect as HookHasEffect, Passive as HookPassive, Layout as HookLayout } from './ReactHookEffectTags';
const HooksDispatcherOnMount = {
useReducer: mountReducer, // 在mount期间,使用mountReducer处理useReducer
useState: mountState,
useEffect: mountEffect,
useLayoutEffect: mountLayoutEffect
const HooksDispatcherOnUpdate = {
useReducer: updateReducer,
useState: updateState,
useEffect: updateEffect,
useLayoutEffect: updateLayoutEffect
function mountLayoutEffect(create, deps) {
return mountEffectImpl(UpdateEffect, HookLayout, create, deps);
function updateLayoutEffect(create, deps) {
return updateEffectImpl(UpdateEffect, HookLayout, create, deps);
# packages/react-reconciler/src/ReactFiberFlags.js
export const LayoutMask = Update;
# packages/react-reconciler/src/ReactFiberWorkLoop.js
import {
commitMutationEffectsOnFiber,
commitPassiveUnmountEffects,
commitPassiveMountEffects,
+ commitLayoutEffects
} from './ReactFiberCommitWork';
function commitRoot(root) {
const { finishedWork } = root;
if ((finishedWork.subtreeFlags & Passive) !== NoFlags || (finishedWork.flags & Passive) !== NoFlags) {
if (!rootDoesHavePassiveEffect) {
rootDoesHavePassiveEffect = true;
scheduleCallback(flushPassiveEffect);
const subtreeHasEffects = (finishedWork.subtreeFlags & MutationMask) !== NoFlags;
const rootHasEffect = (finishedWork.flags & MutationMask) !== NoFlags;
if (subtreeHasEffects || rootHasEffect) {
commitMutationEffectsOnFiber(finishedWork, root);
+ commitLayoutEffects(finishedWork, root);
if (rootDoesHavePassiveEffect) {
rootDoesHavePassiveEffect = false;
rootWithPendingPassiveEffects = root;
root.current = finishedWork;
# packages/react-reconciler/src/ReactFiberCommitWork.js
import { Placement, MutationMask, Update, Passive, LayoutMask } from "./ReactFiberFlags";
import { HasEffect as HookHasEffect, Passive as HookPassive, Layout as HookLayout } from './ReactHookEffectTags';
export function commitMutationEffectsOnFiber(finishedWork, root) {
const current = finishedWork.alternate;
const flags = finishedWork.flags;
switch (finishedWork.tag) {
case FunctionComponent:{
recursivelyTraverseMutationEffects(root, finishedWork);
commitReconciliationEffects(finishedWork);
if (flags & Update) {
commitHookEffectListUnmount(HookHasEffect | HookLayout, finishedWork);
break;
export function commitLayoutEffects(finishedWork, root) {
const current = finishedWork.alternate;
commitLayoutEffectOnFiber(root, current, finishedWork);
function commitLayoutEffectOnFiber(finishedRoot, current, finishedWork) {
const flags = finishedWork.flags;
switch (finishedWork.tag) {
case HostRoot: {
recursivelyTraverseLayoutEffects(finishedRoot, finishedWork);
break;
case FunctionComponent: {
recursivelyTraverseLayoutEffects(finishedRoot, finishedWork);
if (flags & LayoutMask) {
commitHookLayoutEffects(finishedWork, HookHasEffect | HookLayout);
break;
function commitHookLayoutEffects(finishedWork, hookFlags) {
commitHookEffectListMount(hookFlags, finishedWork);
function recursivelyTraverseLayoutEffects(root, parentFiber) {
if (parentFiber.subtreeFlags & LayoutMask) {
let child = parentFiber.child;
while (child !== null) {
const current = child.alternate;
commitLayoutEffectOnFiber(root, current, child);
child = child.sibling;