如何解决React应用中StrictMode导致的双重渲染问题?
问题背景
我有一个简单的React应用,index.js代码如下:
import React from 'react'; import ReactDOM from 'react-dom/client'; import './index.css'; import App from './App'; const root = ReactDOM.createRoot(document.getElementById('root')); root.render( <React.StrictMode> <App /> </React.StrictMode> );
这段代码会导致App组件渲染两次(可通过App中的控制台日志验证)。移除<React.StrictMode>后则仅渲染一次:
import React from 'react'; import ReactDOM from 'react-dom/client'; import './index.css'; import App from './App'; const root = ReactDOM.createRoot(document.getElementById('root')); root.render( //<React.StrictMode> <App /> //</React.StrictMode> );
查阅React官方文档得知:
你的组件会额外重新渲染一次,以发现不纯渲染导致的bug。
你的组件会额外重新运行Effects一次,以发现缺少Effect清理导致的bug。
请问是否有办法阻止StrictMode导致的双重渲染?例如App的子组件中有用setTimeout设置的定时器,双重渲染会导致定时器被创建两次,产生不良副作用,该问题能否修复或规避?
解决方案
1. 不要直接阻止StrictMode的双重渲染
StrictMode的双重渲染是官方故意设计的调试机制,目的是提前暴露代码中的不纯操作(比如在渲染阶段执行副作用、未正确清理Effect等),生产环境下StrictMode的额外渲染会被自动跳过,所以不建议为了规避双重渲染而关闭它。
2. 用Effect清理机制解决定时器重复创建问题
针对定时器这类副作用,React提供的Effect清理机制能完美适配StrictMode的行为:
import { useEffect } from 'react'; function MyComponent() { useEffect(() => { // 创建定时器 const timerId = setTimeout(() => { console.log('定时器执行'); }, 1000); // 返回清理函数:StrictMode会先运行一次Effect,然后立即执行清理函数,再重新运行Effect // 这会自动清除第一次创建的定时器,最终只会保留一个有效定时器 return () => clearTimeout(timerId); }, []); // 空依赖数组表示仅在组件挂载/卸载时执行 return <div>示例组件</div>; }
原理:StrictMode下,React会先执行一次Effect,立刻调用清理函数,再重新执行一次Effect。第一次创建的定时器会被清理,最终只有第二次创建的定时器生效,不会产生重复副作用。
3. 确保渲染函数是纯函数
很多双重渲染的问题根源是在组件渲染阶段(函数组件顶层代码、类组件render方法)执行了副作用操作(比如直接创建定时器、修改全局变量)。这类操作本身违反React设计规则——渲染函数应该是纯函数,不能产生副作用。
正确做法是将所有副作用(定时器、网络请求、DOM操作等)放到useEffect、useLayoutEffect等钩子中执行。
4. 临时关闭StrictMode(仅限调试场景)
如果只是临时调试需要查看正常渲染次数,可以注释掉<React.StrictMode>标签,但调试完成后建议恢复开启,利用StrictMode的调试能力捕获潜在问题。
内容的提问来源于stack exchange,提问作者gib65

