当前位置: 首页 > news >正文

useEffect 和 useLayoutEffect 执行时机

想知道useEffect 和 useLayoutEffect 执行时机,首先必须了解React 组件更新生命周期

1、触发更新

  • setState更新状态
  • 父组件更新等

2、渲染阶段

  • 调用组件函数生成虚拟DOM
  • React进行虚拟DOM对比

3、提交阶段

  • 应用更新DOM(实际修改浏览器DOM)
  • 执行useLayoutEffect清理函数(如有)
  • 执行useLayoutEffect副作用(如有)

4、浏览器绘制

  • 浏览器将更新后的DOM渲染到屏幕上

5、useEffect阶段

  • 执行useEffect函数清理(如有)
  • 执行useEffect副作用(如有)

简单来说:
在这里插入图片描述
关键概念详解

1、浏览器绘制
浏览器绘制是什么:浏览器绘制是计算好的DOM结构和样式实际渲染到浏览器屏幕上的这个过程

  • 计算css样式
  • 生成布局
  • 绘制像素
  • 合成图层

2、同步 vs 异步

useLayoutEffect同步执行

// 伪代码表示React内部处理
function commitWork() {commitDOMUpdates(); // 更新DOMflushLayoutEffects(); // 立即执行所有useLayoutEffectrequestPaint(); // 通知浏览器可以绘制了
}

会阻塞浏览器绘制,直到所有useLayoutEffect执行完成

useEffect异步执行

function scheduleEffect() {afterPaint(() => { // 浏览器绘制后flushPassiveEffects(); // 执行useEffect});
}

通过requestIdleCallback或setTimeout等异步API调度

总结:

特性useEffectuseLayoutEffect
执行时机浏览器绘制后异步执行DOM更新后、浏览器绘制前同步执行
可视化影响可能看到闪烁/布局跳动避免布局跳动
性能影响不阻塞渲染可能阻塞渲染
适用场景数据获取、订阅等普通副作用需要同步DOM操作的场景

场景使用推荐:
使用 useLayoutEffect 的场景

1、测试DOM元素

useLayoutEffect(() => {const rect = ref.current.getBoundingClientRect();setSize(rect);
}, []);

2、同步样式调整

useLayoutEffect(() => {tooltipRef.current.style.left = `${buttonRect.left}px`;
}, [buttonRect]);

3、第三方DOM库集成

useLayoutEffect(() => {thirdPartyLib.init(ref.current);return () => thirdPartyLib.destroy();
}, []);

使用 useEffect 的场景

1、数据获取

useEffect(() => {fetchData().then(setData);
}, []);

2、事件订阅

useEffect(() => {const sub = store.subscribe(handleChange);return () => sub.unsubscribe();
}, []);

3、非关键动画

useEffect(() => {const timer = setTimeout(() => {// 动画逻辑}, 100);return () => clearTimeout(timer);
}, []);

错误场景案例
会看到闪烁的例子,但使用了useEffect

function FlashingComponent() {const [width, setWidth] = useState(100);const divRef = useRef();useEffect(() => {// 在绘制后执行,用户会先看到0宽度,再看到100宽度divRef.current.style.width = '100px';}, []);return <div ref={divRef} style={{ width: 0, background: 'red' }} />;
}

正确的版本:使用useLayoutEffect

function StableComponent() {const divRef = useRef();useLayoutEffect(() => {// 在绘制前执行,用户直接看到最终效果divRef.current.style.width = '100px';}, []);return <div ref={divRef} style={{ width: 0, background: 'green' }} />;
}

为什么SSR中不能使用useLayoutEffect?
因为服务端渲染都没有DOM环境,使用会发出警告。可以先判断有没有dom

// 动态检测环境
const useIsomorphicLayoutEffect = typeof window !== 'undefined' ? useLayoutEffect : useEffect;

如何判断是否需要useLayoutEffect?
主要判断自己的副作用是否会导致布局的变化,如果是则用useLayout,否则用useEffect

为什么react不默认使用useLayoutEffect?
因为同步执行会损害性能,所以react团队会建议默认使用useEffect,除非是需要同步任务执行

http://www.dtcms.com/a/333067.html

相关文章:

  • 【补充】数据库中有关系统编码和校验规则的简述
  • 网络性能排查
  • MC0439符号统计
  • 【web自动化】-2- 浏览器的操作和元素交互
  • 基于vue、node.js、express的网络教学系统设计与实现/基于vue、node.js、express的在线学习系统设计与实现
  • Python实现水文水质预测:Numpy/Matplotlib/TensorFlow实战+神经网络/CNN/RNN/SVM对比+大型水库案例
  • 【.net core】【wetercloud】处理前端项目免登陆,且从前端项目跳转至系统内时的问题
  • 【学习嵌入式day-25-线程】
  • 2020 GPT3 原文 Language Models are Few-Shot Learners 精选注解
  • git推送远程仓库报错:Bad configuration option: \357\273\277include
  • Git报错 “fatal: unable to access CRYPT_E_REVOCATION_OFFLINE (0x80092013)“问题的解决方法
  • 【CV 目标检测】②R-CNN模型
  • C# 中的计时器:Stopwatch 用法解析
  • diffusers学习--stable diffusion的管线解析
  • 第五天~提取Arxml的模板信息
  • react项目性能优化的hook
  • UGUI源码剖析(9):布局的实现——LayoutGroup的算法与实践
  • java程序打包成exe,再打成安装包,没有jdk环境下可运行
  • 【完整源码+数据集+部署教程】孔洞检测系统源码和数据集:改进yolo11-RetBlock
  • 金刚石基植入体新突破!Adv. Funct. Mater. 报道首例增材制造固态摩擦电能量收集器
  • 【FastGTP✨】[01] 使用 FastGPT 搭建简易 AI 应用
  • 部署Qwen-Image,通过API返回可访问的图像URL
  • 以下是对智能电梯控制系统功能及系统云端平台设计要点的详细分析,结合用户提供的梯控系统网络架构设计和系统软硬件组成,分点论述并补充关键要点:
  • 一文打通 AI 知识脉络:大语言模型等关键内容详解
  • 铨林接纸机学习记录1
  • AI智能文档生成系统需求规格说明书
  • Linux 进程、线程与 exec/系统调用详解
  • MySQL中的字符串函数
  • PowerShell 格式化系统完全掌握(下):自定义列/格式字符串/对齐与宽度 + 实战模板
  • 抗日胜利80周年 | HTML页面