资讯动态

React18 函数组件执行顺序、严格模式下重复执行问题

发布时间:2026/10/26 18:23:27 来源:尧图企业网站定制
在 React 中函数组件的执行顺序和“为什么会执行两次”是很多人升级到 React18 后最容易困惑的问题之一。一、React18 函数组件执行顺序先看一个典型例子import { useEffect, useLayoutEffect, useState } from react; export default function App() { console.log(1. 组件函数执行); const [count, setCount] useState(() { console.log(2. useState 初始化); return 0; }); useLayoutEffect(() { console.log(3. useLayoutEffect); }, []); useEffect(() { console.log(4. useEffect); }, []); return ( div onClick{() setCount(count 1)} {count} /div ); }正常模式下首次渲染顺序执行结果1. 组件函数执行 2. useState 初始化 3. useLayoutEffect 4. useEffect二、React18 渲染阶段与提交阶段React18 可以分成1. Render 阶段渲染阶段这一阶段执行函数组件执行 hooks生成 Virtual DOM这里不能做副作用❌ 不要fetch() localStorage.setItem() 订阅事件因为 React 可能中断 render重试 render丢弃 render所以 render 必须纯净。2. Commit 阶段提交阶段React 真正更新 DOM。然后执行useLayoutEffect ↓ 浏览器绘制 ↓ useEffect三、useLayoutEffect 与 useEffect 顺序useLayoutEffect同步执行。DOM 更新后立即执行浏览器还没绘制。适合DOM 测量scroll动画定位useEffect异步执行。浏览器绘制完成后执行。适合请求订阅日志四、为什么 React18 会执行两次这是最核心的问题。React18 StrictMode 开启后开发环境下React.StrictMode App / /React.StrictModeReact 会故意组件 mount → unmount → 再 mount目的检查副作用是否安全cleanup 是否完整是否有不纯 render五、React18 严格模式下真实执行顺序示例function App() { console.log(render); useEffect(() { console.log(effect); return () { console.log(cleanup); }; }, []); return divhello/div; }开发环境 StrictMode输出render render effect cleanup effect六、为什么 render 执行两次React18 在开发环境会Double Invoke双调用包括函数组件useState initializeruseMemouseReducer initializer例如const [state] useState(() { console.log(init); return 0; });会输出init init七、哪些会重复执行会重复1. 函数组件function App() {}2. useEffectuseEffect(() {})会执行 cleanup 再执行3. useLayoutEffect同样也会。4. useState 初始化函数useState(() {})5. useMemouseMemo(() {})八、生产环境会不会不会。严格模式双执行✅ 仅开发环境❌ 生产环境不会所以npm run build后不会重复。九、为什么 React 要这样设计React18 引入Concurrent Rendering并发渲染未来 React 可能暂停 render恢复 render重试 render丢弃 render所以 React 需要确保render 必须是“纯函数”即相同输入 → 相同输出不能有副作用。十、最容易踩坑的地方1. useEffect 发请求两次例如useEffect(() { fetch(/api/user); }, []);开发环境会请求两次。正确理解不是 bug。是 StrictMode 检查副作用。十一、如何避免请求两次方法1接受它推荐这是 React 官方推荐。因为生产环境不会重复。方法2使用 ref 防重复const hasRequest useRef(false); useEffect(() { if (hasRequest.current) return; hasRequest.current true; fetchData(); }, []);方法3封装请求层缓存例如SWRReact Query它们天然去重。例如TanStack Query 官方文档SWR 官方文档十二、React18 完整生命周期顺序函数组件首次挂载render ↓ 生成 Virtual DOM ↓ DOM commit ↓ useLayoutEffect ↓ 浏览器 paint ↓ useEffect更新时render ↓ diff ↓ commit ↓ cleanup(old effect) ↓ new effect卸载时cleanup十三、StrictMode 下的核心记忆开发环境mount ↓ effect ↓ cleanup ↓ 重新 mount ↓ effectReact 是故意模拟卸载重建。十四、面试高频总结React18 为什么组件执行两次答案React18 在开发环境下的 StrictMode 中会故意对组件进行 mount → unmount → remount用于检测副作用与不安全代码为 Concurrent Rendering 做准备。useEffect 为什么执行两次因为 StrictMode 会重新挂载组件所以 effect 会重新执行一次。生产环境会吗不会仅开发环境。十五、最佳实践render 阶段不要做fetch() setTimeout() addEventListener() localStorage.setItem()effect 中一定要 cleanupuseEffect(() { const timer setInterval(() {}, 1000); return () clearInterval(timer); }, []);推荐render 保持纯净effect 做副作用cleanup 做释放接受 StrictMode 双执行十六、推荐官方资料React 官方 StrictMode 文档React 官方 useEffect 文档React 官方渲染机制说明

读完文章,也想定制专属网站?

尧图设计师 24 小时内与您沟通定制方案

免费获取报价 →
↑