React组件点击按钮后为何渲染两次?如何避免重复执行?
组件重复渲染与事件重复触发的原因及解决办法
为什么会出现重复渲染和事件重复处理?
开发环境下React的**严格模式(StrictMode)**会刻意执行两次组件渲染、两次状态更新回调函数,这是React内置的调试机制——用来帮你排查代码中的非纯操作(比如状态更新逻辑里包含副作用、意外的重复执行行为)。这种行为只会在开发环境存在,生产环境下会自动消失,不会影响线上用户。你代码里的状态更新回调被调用两次、组件渲染两次,都是Strict Mode导致的。
解决办法
1. 调整Strict Mode(可选)
如果只是开发时不想看到这个现象,找到项目根组件(比如index.tsx)里的<React.StrictMode>标签删掉即可。但不推荐这么做,因为Strict Mode能提前帮你发现很多潜在的代码问题。
2. 保证状态更新是纯函数
状态更新的回调函数应该是纯函数,不能包含副作用(比如你把console.log放在状态更新回调里就不合适)。把副作用移到外部或者用useEffect监听状态变化:
const handleSimpleAdd = () => { console.log('handleSimpleAdd'); // 移到这里,每次点击只会执行一次 setSimpleData((prev) => prev + 1); };
或者用useEffect监听状态变化来处理副作用:
useEffect(() => { console.log('simpleData 更新为:', simpleData); }, [simpleData]);
3. 优化子组件不必要渲染
每次App组件渲染时,传递给SimpleForm的onAdd是新的匿名函数,导致子组件每次都被迫重新渲染。可以通过两步优化:
- 用
React.memo包裹SimpleForm,让它只在props真正变化时重新渲染 - 用
useCallback缓存handleSimpleAdd函数,保持函数引用稳定
修改后的完整代码:
import React, { useCallback, useEffect } from 'react'; interface SimpleFormProps { data: number; onAdd: () => void; } // React.memo包裹子组件,减少不必要渲染 const SimpleForm = React.memo(({ data, onAdd }: SimpleFormProps) => { return ( <form> {data} <button type="button" onClick={onAdd}> Simple Add </button> </form> ); }); export default function App() { const [simpleData, setSimpleData] = React.useState(10); // useCallback缓存函数,保持引用稳定 const handleSimpleAdd = useCallback(() => { console.log('handleSimpleAdd'); setSimpleData((prev) => prev + 1); }, []); useEffect(() => { console.log('simpleData 更新为:', simpleData); }, [simpleData]); return ( <div> <SimpleForm data={simpleData} onAdd={handleSimpleAdd} /> </div> ); }
内容的提问来源于stack exchange,提问作者Jake
相关产品推荐
相关产品推荐

