React场景下子组件Timer与父组件通信实现答题后重置计时器
解决答题应用中切换题目时计时器不重置的问题
问题核心在于两处:
- Timer组件未监听
currentPage的变化,父组件切换题目时,Timer内部的timer状态不会自动重置为10; - 原Timer组件的定时器逻辑存在闭包问题,且依赖项设置不合理,导致计时器更新逻辑不符合预期。
修正方案
通过以下两处关键修改解决问题:
- 给Timer组件添加监听
currentPage变化的副作用,题目切换时强制重置计时器; - 优化定时器管理逻辑,使用
useRef保存定时器ID,配合函数式更新获取最新timer值,解决闭包与不必要的定时器重建问题。
修正后的完整代码
const { useState, useEffect, useRef } = React; const questions = [ { questionText: "What is the capital city of France", answerOptions: [ { id: 1, answerText: "New York", isCorrect: false }, { id: 2, answerText: "London", isCorrect: false }, { id: 3, answerText: "Paris", isCorrect: true }, { id: 4, answerText: "Dublin", isCorrect: false } ] }, { questionText: "Who is CEO of Tesla?", answerOptions: [ { id: 1, answerText: "Jeff Bezos", isCorrect: false }, { id: 2, answerText: "Elon Musk", isCorrect: true }, { id: 3, answerText: "Bill Gates", isCorrect: false }, { id: 4, answerText: "Tony Stark", isCorrect: false } ] } ]; const App = () => { const [currentPage, setCurrentPage] = useState(0); const handleAnswerCorrectness = () => { if (currentPage + 1 < questions.length) { setCurrentPage((prevState) => prevState + 1); } }; return ( <div className="App"> <div> <h3> Question {currentPage + 1}/{questions.length} </h3> <Timer currentPage={currentPage} onCurrentPageChange={setCurrentPage} questionsLength={questions.length} /> </div> <p>{questions[currentPage].questionText}</p> <div> {questions[currentPage].answerOptions.map((answerOption) => ( <button key={answerOption.id} onClick={handleAnswerCorrectness}> {answerOption.answerText} </button> ))} </div> </div> ); } const Timer = ({ onCurrentPageChange, currentPage, questionsLength }) => { const [timer, setTimer] = useState(10); const intervalRef = useRef(null); // 监听题目切换,重置计时器 useEffect(() => { setTimer(10); }, [currentPage]); // 管理定时器生命周期 useEffect(() => { // 清除旧定时器 if (intervalRef.current) { clearInterval(intervalRef.current); } // 启动新定时器 intervalRef.current = setInterval(() => { setTimer(prevTimer => { if (prevTimer <= 1) { // 时间到期切换题目 if (currentPage + 1 < questionsLength) { onCurrentPageChange(prev => prev + 1); } return 10; } return prevTimer - 1; }); }, 1000); // 组件卸载或依赖变化时清理定时器 return () => clearInterval(intervalRef.current); }, [currentPage, onCurrentPageChange, questionsLength]); return ( <div> <span>{timer}</span> </div> ); }; const root = ReactDOM.createRoot( document.getElementById("root") ).render(<App/>);
<div id="root"></div> <script src="https://cdnjs.cloudflare.com/ajax/libs/react/18.1.0/umd/react.development.js"></script> <script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/18.1.0/umd/react-dom.development.js"></script>
关键修改说明
- 监听currentPage重置计时器:新增的useEffect依赖
currentPage,父组件切换题目时自动将timer重置为10,解决点击答题按钮后计时器不重置的问题; - useRef管理定时器:用ref存储定时器ID,避免每次timer变化都重建定时器,同时确保组件卸载时正确清理定时器,防止内存泄漏;
- 函数式更新timer:通过函数式更新获取最新的timer值,解决闭包导致的逻辑错误;
- 修正参数拼写:将原
questionsLenght改为questionsLength,避免拼写错误引发的异常。
内容的提问来源于stack exchange,提问作者Adrian
相关产品推荐
相关产品推荐

