You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

React场景下子组件Timer与父组件通信实现答题后重置计时器

解决答题应用中切换题目时计时器不重置的问题

问题核心在于两处:

  1. Timer组件未监听currentPage的变化,父组件切换题目时,Timer内部的timer状态不会自动重置为10;
  2. 原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>

关键修改说明

  1. 监听currentPage重置计时器:新增的useEffect依赖currentPage,父组件切换题目时自动将timer重置为10,解决点击答题按钮后计时器不重置的问题;
  2. useRef管理定时器:用ref存储定时器ID,避免每次timer变化都重建定时器,同时确保组件卸载时正确清理定时器,防止内存泄漏;
  3. 函数式更新timer:通过函数式更新获取最新的timer值,解决闭包导致的逻辑错误;
  4. 修正参数拼写:将原questionsLenght改为questionsLength,避免拼写错误引发的异常。

内容的提问来源于stack exchange,提问作者Adrian

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.09 15:20:37