React useState使用疑问:定时器中更新count状态始终为0原因求解
问题原因
- 核心是React函数组件闭包陷阱:触发
chrono函数时,当前渲染周期闭包里的count为初始值0,setInterval的回调函数会永久持有该闭包的引用,后续每次执行回调读取的都是被捕获的旧值0,和更新后的state无关。 - 隐藏问题:未存储定时器ID,多次点击会生成多个并行定时器导致计数异常,组件卸载时也无法清理定时器会造成内存泄漏。
修复方案
做两处核心调整即可:
setCount改用函数式更新写法,入参可以直接拿到最新的state值,不受闭包旧值影响- 用
useRef存储定时器ID,实现定时器启停控制和卸载清理
修改后完整App组件代码
import { Button } from './components/Button'; import { useState, useEffect, useRef } from 'react'; function App() { const [count, setCount] = useState(0); // 用ref存储定时器ID,跨渲染周期保持引用不变 const timerRef = useRef(null); const chrono = () => { // 启动前清理已有定时器,避免多个并行运行 if (timerRef.current) clearInterval(timerRef.current); timerRef.current = setInterval(() => { // 函数式更新,每次读取最新的count值 setCount(prevCount => prevCount + 1); }, 1000); } // 组件卸载时清理定时器,避免内存泄漏 useEffect(() => { return () => { if (timerRef.current) clearInterval(timerRef.current); } }, []) // 若需要打印最新的count值,单独用useEffect监听count变化即可 useEffect(() => { console.log(count); }, [count]) return ( <> <Button clicAction={chrono} nom="Start the timer"/> <p>{count}</p> </> ); } export default App;
小提示:你的Button组件里导入的
useState没有被使用,可以直接删掉,不会影响现有功能。
内容的提问来源于stack exchange,提问作者JSL
相关产品推荐
相关产品推荐

