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

React中如何避免变量在组件每次重渲染时被重新初始化

核心问题定位

你在App组件函数内部用let定义了questions数组,每次组件重渲染时,整个函数体都会从头执行,重新把数组赋值为内置的初始题目列表——不管之前在checkAnswer里对duration做过什么修改,只要触发重渲染(比如每秒执行的setQuizTime),数组就会被重置为每个题duration默认15的初始状态。

修正方向

  • 不要把需要持久保存的可变数据写在组件内部的普通变量里,这类变量的生命周期和组件函数的执行绑定,每次重渲染都会被重新初始化。
  • 用useState管理questions数组的状态,这类状态会被React保存,跨重渲染不会丢失。
  • 所有对题目属性的修改,都要通过setQuestions生成新的状态对象完成,不要直接修改原数组里的对象属性——既符合React的状态追踪规则,也能避免可变引用带来的状态混乱。
  • 如果需要让题目列表全局可访问,只要把这个由useState管理的状态放到上层的Context Provider里,或者用独立的全局状态库托管,就可以实现跨组件读取,不会影响状态的持久保存。

顺带修正的原有代码问题

  • 原useEffect的清理逻辑错误:之前在clearTimeout里传入的是quizTime的数值,不是定时器的实际ID,会导致定时器无法正确清理,出现内存泄漏。
  • 原findMaxQuestion的遍历逻辑有bug:初始max为undefined时的分支判断会导致最大值对比失效,简化为reduce实现可以避免这个问题。
  • 原代码没有在初始题目对象上显式定义duration属性,要靠findMaxQuestion动态补默认值,直接在初始题目配置里定义duration:15更清晰。

修正后的参考代码

// 把初始题目数组移到组件外部,只初始化一次,避免每次重渲染重新生成
const initialQuestions = [
  {
    questionText: 'What is the capital of France?',
    answerOptions: [
      { answerText: 'New York', isCorrect: false },
      { answerText: 'London', isCorrect: false },
      { answerText: 'Paris', isCorrect: true },
      { answerText: 'Dublin', isCorrect: false },
    ],
    duration: 15
  },
  {
    questionText: 'Who is CEO of Tesla?',
    answerOptions: [
      { answerText: 'Jeff Bezos', isCorrect: false },
      { answerText: 'Elon Musk', isCorrect: true },
      { answerText: 'Bill Gates', isCorrect: false },
      { answerText: 'Tony Stark', isCorrect: false },
    ],
    duration: 15
  },
  {
    questionText: 'The iPhone was created by which company?',
    answerOptions: [
      { answerText: 'Apple', isCorrect: true },
      { answerText: 'Intel', isCorrect: false },
      { answerText: 'Amazon', isCorrect: false },
      { answerText: 'Microsoft', isCorrect: false },
    ],
    duration: 15
  },
  {
    questionText: 'How many Harry Potter books are there?',
    answerOptions: [
      { answerText: '1', isCorrect: false },
      { answerText: '4', isCorrect: false },
      { answerText: '6', isCorrect: false },
      { answerText: '7', isCorrect: true },
    ],
    duration: 15
  },
];

function App() {
  // 用useState管理题目列表,状态跨重渲染持久保留
  const [questions, setQuestions] = useState(initialQuestions);
  const [quizTime, setQuizTime] = useState(90) // in seconds

  useEffect(() => {
    if (quizTime <= 0) return;
    // 保存定时器ID,清理函数清除正确的ID
    const timerId = setTimeout(() => setQuizTime(prevTime => prevTime - 1), 1000);
    return () => clearTimeout(timerId);
  }, [quizTime]);
  
  function checkAnswer(answer, question, time) {
    if (answer == null) return;
    const longerThanHalf = question.duration - time > question.duration / 2;
    let newDuration = question.duration;
    
    if (answer.isCorrect) {
      newDuration = longerThanHalf 
        ? Math.max(question.duration - 2, 5)
        : Math.max(question.duration - 1, 5);
    }
    
    // 生成新的状态数组更新,不直接修改原对象
    setQuestions(prevQuestions => prevQuestions.map(q => 
      q.questionText === question.questionText 
        ? { ...q, duration: newDuration }
        : q
    ));
  };

  const findMaxQuestion = () => {
    // 简化最大值查找逻辑,避免初始值判断错误
    return questions.reduce((max, current) => 
      current.duration > max.duration ? current : max
    , questions[0]);
  }

  if (quizTime <= 0) {
    return <div>测验结束</div>
  }
  
  const maxQuestion = findMaxQuestion();
  return (
    <div className="container">
      <div>{quizTime} seconds left</div>
      <FlashCard question = {maxQuestion} checkAnswer = {checkAnswer}/>
    </div>
  );
}

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.28 22:36:07