如何解决useEffect使用props传递函数引发的react-hooks/exhaustive-deps警告?
解决React useEffect的exhaustive-deps警告问题
你的问题核心是useEffect中调用了props.onCountdownEnd但未将其加入依赖数组,直接添加整个props到依赖会导致不必要的副作用重触发(比如props.seconds变化时会重置倒计时),正确的处理方式如下:
步骤1:解构props并指定精准依赖
不要把整个props加入依赖数组,而是单独解构出onCountdownEnd作为依赖,同时优化setCount的更新方式,避免依赖count:
function Countdown(props: { seconds: number; onCountdownEnd: () => void }) { const { seconds, onCountdownEnd } = props; const [count, setCount] = useState(seconds); useEffect(() => { // 初始检查是否已经是0 if (count === 0) { onCountdownEnd(); return; } const intervalId = setInterval(() => { // 使用函数式更新,获取最新状态值,无需依赖count setCount(prevCount => { if (prevCount <= 1) { // 倒计时结束时清除定时器并触发回调 clearInterval(intervalId); onCountdownEnd(); return 0; } return prevCount - 1; }); }, 1000); return () => clearInterval(intervalId); }, [onCountdownEnd]); // 仅依赖onCountdownEnd,无需count return <span className="text-xxl">00:0{count}</span>; }
关键优化点说明
- 精准依赖:只把用到的
onCountdownEnd加入依赖数组,避免整个props带来的不必要重渲染。 - 函数式状态更新:
setCount(prevCount => ...)可以直接获取最新的状态值,不需要将count加入依赖,同时解决了定时器闭包捕获旧状态的问题。 - 及时清理定时器:当倒计时即将结束(
prevCount <=1)时,提前清除定时器,避免无效的定时器执行,同时触发结束回调。 - 初始状态检查:如果传入的
seconds本身就是0,直接触发结束回调。
额外说明
如果你的onCountdownEnd是父组件传递的内联函数(比如() => setSomeState(...)),每次父组件渲染都会生成新的函数,导致子组件的useEffect重复触发。这种情况下可以用useCallback包裹父组件的回调函数,避免不必要的重渲染:
父组件中:
const handleCountdownEnd = useCallback(() => { // 你的结束逻辑 }, []); <Countdown seconds={10} onCountdownEnd={handleCountdownEnd} />
内容的提问来源于stack exchange,提问作者bbbonthemoon
相关产品推荐
相关产品推荐

