怎么用dw做可上传文件的网站,做网站怎么不被找到,文登做网站,湖南营销网站建设上篇文章记录了useState钩子函数的源码#xff0c;这篇文章记录 useEffect、useLayoutEffect 和 useInsertionEffect 钩子函数#xff0c;主要看看它们的源码实现、区别和应用场景。
useEffect#xff1a;useEffect – React 中文文档
useLayoutEffect#xff1a;useLayo…上篇文章记录了useState钩子函数的源码这篇文章记录 useEffect、useLayoutEffect 和 useInsertionEffect 钩子函数主要看看它们的源码实现、区别和应用场景。
useEffectuseEffect – React 中文文档
useLayoutEffectuseLayoutEffect – React 中文文档
useInsertionEffectuseInsertionEffect – React 中文文档
useEffect
useEffect 是 React 中用于处理 副作用 的核心 Hook主要用于执行与渲染无关的操作。
function useEffect(create: () (() void) | void,deps: Arraymixed | void | null,
): void {const dispatcher resolveDispatcher();return dispatcher.useEffect(create, deps);
}mountEffect
mountEffect 函数是 React 中用于在组件挂载阶段执行副作用操作的钩子函数。在 React 里副作用操作可以是数据获取、订阅事件、手动修改 DOM 等。mountEffect 会在组件首次渲染到 DOM 之后执行副作用函数并且可以选择性地指定依赖项数组用于控制副作用函数的重新执行。 函数参数含义 create这是一个必需的参数是一个函数。该函数会在组件挂载后执行它可以返回一个可选的清理函数类型为 () void用于在组件卸载时执行清理操作比如取消订阅、清除定时器等。如果不需要清理操作create 函数可以不返回任何值即返回 void。deps这是一个可选参数类型可以是数组Arraymixed、void 或者 null。deps 数组中的元素是副作用函数依赖的值。如果 deps 数组为空副作用函数只会在组件挂载和卸载时执行如果 deps 数组中的某个值发生变化副作用函数会在组件重新渲染后再次执行。 function mountEffect(create: () (() void) | void,deps: Arraymixed | void | null,
): void {mountEffectImpl(// 这是一个标志位用于表示副作用的类型。// PassiveEffect 通常表示副作用是被动执行的即不会阻塞渲染过程//PassiveStaticEffect 可能与静态副作用相关。PassiveEffect | PassiveStaticEffect,HookPassive,// HookPassive也是一个标志用于标识这是一个被动的钩子类型create,// 回调函数deps,// 依赖项数组);
}
mountEffectImpl 函数
mountEffectImpl 函数是 React 内部用于实现副作用钩子如 useEffect 在挂载阶段的核心逻辑。它主要负责初始化钩子状态、设置 Fiber 节点的标志位并将副作用信息存储在钩子的 memoizedState 中。 函数参数说明 fiberFlags类型为 Flags是一个标志位用于标识当前 Fiber 节点上副作用的类型和状态。不同的标志位组合可以表示不同的副作用行为例如是否是被动副作用、是否需要立即执行等。hookFlags类型为 HookFlags用于标识当前钩子的类型和状态与 fiberFlags 类似但更侧重于钩子本身的特性。create是一个函数在组件挂载后会执行这个函数来产生副作用。它可以返回一个可选的清理函数类型为 () void用于在组件卸载或副作用重新执行之前清理之前的副作用。deps依赖项数组类型为 Arraymixed | void | null。它决定了副作用函数在什么情况下会重新执行。如果 deps 为 undefined 或 null副作用函数会在每次渲染时都执行如果 deps 是一个空数组副作用函数只会在组件挂载和卸载时执行如果 deps 数组中有值当这些值发生变化时副作用函数会重新执行。 function mountEffectImpl(fiberFlags: Flags,hookFlags: HookFlags,create: () (() void) | void,deps: Arraymixed | void | null,
): void {// 创建并返回当前hookconst hook mountWorkInProgressHook();// 如果 deps 为 undefined将 nextDeps 赋值为 null否则将 deps 赋值给 nextDepsconst nextDeps deps undefined ? null : deps;// currentlyRenderingFiber 表示当前正在渲染的 Fiber 节点。通过按位或操作将 fiberFlags 合并到 currentlyRenderingFiber.flags 中标记当前 Fiber 节点上存在特定类型的副作用。currentlyRenderingFiber.flags | fiberFlags;// pushEffect是 React 内部的一个函数用于将副作用信息存储到一个链表中。hook.memoizedState pushEffect(HookHasEffect | hookFlags,//标志位create,// 副作用函数createEffectInstance(),//创建一个副作用实例对象该对象可能包含副作用的相关信息如清理函数等。nextDeps,// 依赖项数字);
}pushEffect 函数
pushEffect 函数是 React 内部用于将副作用信息添加到当前正在渲染的 Fiber 节点的更新队列中的核心函数。在 React 的函数式组件中副作用如 useEffect 产生的副作用会被组织成一个循环链表pushEffect 函数负责创建副作用对象并将其插入到这个链表中。 函数参数说明 tag类型为 HookFlags是一个标志位用于标识副作用的类型和状态例如是否需要执行、是否是被动副作用等。create是一个函数用于创建副作用。这个函数在副作用执行时会被调用并且它可以返回一个可选的清理函数用于在副作用重新执行或组件卸载时清理之前的副作用。inst类型为 EffectInstance是一个副作用实例对象可能包含一些与副作用相关的元数据。deps依赖项数组类型为 Arraymixed | null。它决定了副作用在什么情况下会重新执行。如果 deps 为 null副作用会在每次渲染时都执行如果 deps 是一个数组当数组中的值发生变化时副作用会重新执行。 function pushEffect(tag: HookFlags,create: () (() void) | void,inst: EffectInstance,deps: Arraymixed | null,
): Effect {// 创建一个 Effect 类型的对象 effect包含了副作用的各种信息如标志位 tag、创建函数 create、副作用实例 inst、依赖项数组 deps以及一个指向下一个副作用对象的指针 next初始化为 nullconst effect: Effect {tag,create,inst,deps,// Circularnext: (null: any),};// currentlyRenderingFiber 表示当前正在渲染的 Fiber 节点。//首先尝试从 currentlyRenderingFiber 的 updateQueue 属性中获取更新队列 componentUpdateQueue。let componentUpdateQueue: null | FunctionComponentUpdateQueue (currentlyRenderingFiber.updateQueue: any);// 若更新队列为 null则调用 createFunctionComponentUpdateQueue 函数创建一个新的更新队列并将其赋值给 currentlyRenderingFiber 的 updateQueue 属性。if (componentUpdateQueue null) {componentUpdateQueue createFunctionComponentUpdateQueue();currentlyRenderingFiber.updateQueue (componentUpdateQueue: any);}const lastEffect componentUpdateQueue.lastEffect;// 如果 lastEffect 为 null说明更新队列中还没有副作用对象此时将 effect 的 next 指针指向自身形成一个只有一个节点的循环链表并将 componentUpdateQueue 的 lastEffect 指向 effect。if (lastEffect null) {componentUpdateQueue.lastEffect effect.next effect;} else {// 构建循环队列const firstEffect lastEffect.next;lastEffect.next effect;effect.next firstEffect;componentUpdateQueue.lastEffect effect;}// 返回创建并插入到链表中的副作用对象。return effect;
}
createFunctionComponentUpdateQueue
React 中 函数组件更新队列 的创建逻辑主要根据特性开关 enableUseMemoCacheHook 决定是否包含 memoCache 字段。
let createFunctionComponentUpdateQueue: () FunctionComponentUpdateQueue;
// 一个布尔型特性开关控制是否启用 useMemo 和 useCallback 的缓存优化。
if (enableUseMemoCacheHook) {createFunctionComponentUpdateQueue () {// 启用缓存优化的结构return {lastEffect: null, // 最后一个副作用链表events: null, // 事件处理相关状态stores: null, // 事件处理相关状态memoCache: null, // memo 缓存新增字段};};
} else {createFunctionComponentUpdateQueue () {// 传统结构return {lastEffect: null,events: null,stores: null,};};
}
updateEffect
React 中 useEffect Hook 的 更新阶段 实现主要用于 注册副作用 并在后续渲染时决定是否重新执行。
function updateEffect(create: () (() void) | void,deps: Arraymixed | void | null,
): void {// PassiveEffect表示这是一个异步副作用在浏览器绘制后执行。// HookPassive标记 Hook 类型为 useEffect。// create副作用创建函数。updateEffectImpl(PassiveEffect, HookPassive, create, deps);
}
updateEffectImpl
React 中 useEffect 和 useLayoutEffect 的 核心实现主要负责 注册、更新和比较副作用。
function updateEffectImpl(fiberFlags: Flags,hookFlags: HookFlags,create: () (() void) | void,deps: Arraymixed | void | null,
): void {// 获取当前 Hook 并准备依赖数组const hook updateWorkInProgressHook();const nextDeps deps undefined ? null : deps;const effect: Effect hook.memoizedState;// 存储副作用的实例信息可能包含上一次的 cleanup 函数。const inst effect.inst;// currentHook is null on initial mount when rerendering after a render phase// state update or for strict mode.if (currentHook ! null) {if (nextDeps ! null) {const prevEffect: Effect currentHook.memoizedState;const prevDeps prevEffect.deps;if (areHookInputsEqual(nextDeps, prevDeps)) {// 依赖未变化仅添加 hookFlags不包含 HookHasEffect//hookFlags, 此时副作用仅被存储不会在提交阶段执行。hook.memoizedState pushEffect(hookFlags, create, inst, nextDeps);return;}}}// 标记 Fiber 并创建副作用// 对于 useEffectPassiveEffect异步执行。// 对于 useLayoutEffectLayoutEffect同步执行。currentlyRenderingFiber.flags | fiberFlags;hook.memoizedState pushEffect(// HookHasEffect标记该副作用需要在提交阶段执行。HookHasEffect | hookFlags,create,inst,nextDeps,);
}
useLayoutEffect
function useLayoutEffect(create: () (() void) | void,deps: Arraymixed | void | null,
): void {const dispatcher resolveDispatcher();return dispatcher.useLayoutEffect(create, deps);
}
mountLayoutEffect
React 中 useLayoutEffect Hook 的 挂载阶段 实现主要用于 注册同步执行的副作用。
function mountLayoutEffect(create: () (() void) | void,deps: Arraymixed | void | null,
): void {// UpdateEffect表示该 Fiber 需要执行副作用。// LayoutStaticEffect表示这是一个布局副作用需要同步执行。let fiberFlags: Flags UpdateEffect | LayoutStaticEffect;return mountEffectImpl(fiberFlags, HookLayout, create, deps);
}
updateLayoutEffect
React 中 useLayoutEffect Hook 的 更新阶段 实现主要用于 比较依赖项 并决定是否需要更新或执行副作用。
function updateLayoutEffect(create: () (() void) | void,deps: Arraymixed | void | null,
): void {// UpdateEffect表示该 Fiber 需要执行副作用。// HookLayout标记为 useLayoutEffect 类型的副作用。// create副作用创建函数。return updateEffectImpl(UpdateEffect, HookLayout, create, deps);
} useInsertionEffect
useInsertionEffect 是 React 18 新增的 Hook用于在 DOM 插入后、布局计算前执行副作用。它主要用于 CSS-in-JS 库注入动态样式以避免 布局抖动Layout Shift。
function useInsertionEffect(create: () (() void) | void,deps: Arraymixed | void | null,
): void {const dispatcher resolveDispatcher();return dispatcher.useInsertionEffect(create, deps);
}mountInsertionEffect
React 中 useInsertionEffect Hook 的 挂载阶段 实现主要用于 在 DOM 插入后、布局计算前执行副作用。
function mountInsertionEffect(create: () (() void) | void,deps: Arraymixed | void | null,
): void {// UpdateEffect表示该 Fiber 需要执行副作用。// HookInsertion标记为插入阶段的副作用useInsertionEffect。mountEffectImpl(UpdateEffect, HookInsertion, create, deps);
} updateInsertionEffect
React 中 useInsertionEffect Hook 的 更新阶段 实现主要用于 在 DOM 插入后、布局计算前执行副作用并在依赖项变化时重新执行。
function updateInsertionEffect(create: () (() void) | void,deps: Arraymixed | void | null,
): void {return updateEffectImpl(UpdateEffect, HookInsertion, create, deps);
}全局常量之 Hook 副作用类型 的位掩码常量
React 中 Hook 副作用类型 的位掩码常量用于标记副作用的 执行时机 和 状态。
export type HookFlags number;export const NoFlags /* */ 0b0000;// Represents whether effect should fire.
// 标记副作用需要执行。
export const HasEffect /* */ 0b0001;// Represents the phase in which the effect (not the clean-up) fires.
// 插入副作用首次挂载时执行。
export const Insertion /* */ 0b0010;// 布局副作用同步执行。
export const Layout /* */ 0b0100;// 异步副作用浏览器绘制后执行。
export const Passive /* */ 0b1000; useEffect 与 useLayoutEffect 的执行时机 useEffect 与 useLayoutEffect 的应用场景及说明 useEffect 与 useLayoutEffect 在组件中执行顺序
1、在组件 首次渲染 时
DOM 更新React 更新 DOM 节点。useLayoutEffect同步执行可访问最新 DOM。浏览器绘制浏览器根据更新后的 DOM 绘制页面。useEffect异步执行。 2、在组件 更新 时
DOM 更新React 更新 DOM 节点。上一次 useLayoutEffect 的 cleanup同步执行。本次 useLayoutEffect同步执行。浏览器绘制浏览器绘制页面。上一次 useEffect 的 cleanup异步执行。本次 useEffect异步执行。 useEffect、useLayoutEffect、useInsertionEffect三者 的区别