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

React组件state更新重渲染时props随机值未重新生成问题

React类组件重渲染时随机题目值不更新问题排查

问题场景

传入App组件的props.value1、props.value2、props.value3初始值均通过Math.floor(Math.random() * 100)生成,组件构造函数中结合三个props值计算得到this.proposedAnswer作为算术题的待验证答案。点击True/False按钮时会调用setState更新numQuestions(答题总数)、numCorrect(答对题数)两个状态值,已知setState会触发组件render方法执行,但实际每次点击按钮触发重渲染时,value1、value2、value3三个随机值并未重新生成、数值不会随按钮点击发生变化。

问题对应代码

class App extends Component {
      constructor(props) {
      super(props)
      this.proposedAnswer = Math.floor(Math.random() * 3) + this.props.value1 + this.props.value2 + this.props.value3;
      this.state = {
        numQuestions : 0,
        numCorrect : 0,
      }
   }

   rightanswer= ()=> {
        if(this.proposedAnswer === this.props.value1 + this.props.value2 + this.props.value3){
          this.setState((oldstate)=> ({
            numCorrect : oldstate.numCorrect +=1 ,
            numQuestions : oldstate.numQuestions += 1 ,
          }))
        }else{
             this.setState((oldstate)=> ({
             numQuestions : oldstate.numQuestions += 1 ,
         }))
     }
  }

   falseanswer= ()=> {
         if(this.proposedAnswer !== this.props.value1 + this.props.value2 + this.props.value3){
           this.setState((oldstate)=> ({
               numCorrect : oldstate.numCorrect +=1 ,
               numQuestions : oldstate.numQuestions += 1 ,
           }))
         }else{
               this.setState((oldstate)=> ({
               numQuestions : oldstate.numQuestions += 1 ,
         }))
        }
      }

   render() {
      return (
          <div className="App">
            <div className="game">
              <h2>Mental Math</h2>
              <div className="equation">
                  <p className="text">{`${this.props.value1} + ${this.props.value2} + 
                   ${this.props.value3} = ${this.proposedAnswer}`}</p>
              </div>
              <button  onClick={() => this.rightanswer()}>True</button>
              <button onClick={() => this.falseanswer()}>False</button>
              <p className="text">
                 Your Score: {this.state.numCorrect}/{this.state.numQuestions}
              </p>
             </div>
          </div>
       );
      }
    }

  export default App;

根本原因

这个现象完全符合React类组件的执行逻辑,不存在渲染异常:

  • 类组件的constructor构造函数仅在组件首次挂载时执行1次,后续所有重渲染都不会重新触发构造函数。代码中在构造函数里赋值的this.proposedAnswer只会在组件初始化时计算一次,重渲染过程中这个值不会自动更新。
  • value1、value2、value3是父组件传入的props,props的更新权完全归属父组件:生成三个随机数的Math.random()逻辑写在父组件中,只有父组件自身触发重渲染时,才会重新执行随机数计算、把新值传给App组件。当前App组件内部调用setState只会触发自身重渲染,不会影响父组件的执行逻辑,父组件不重渲染,传入的props值自然不会变化。
  • 代码存在额外隐患:setState的更新回调中直接通过+=修改旧状态对象oldstate的属性,违反React状态不可变原则,容易引发状态更新不同步、渲染结果不符合预期的问题。

修复方案

  • 移除父组件生成随机数传props的逻辑,把题目相关的value1、value2、value3、proposedAnswer全部放到App组件自身的state中管理。
  • 封装独立的新题目生成方法,组件初始化时调用一次生成第一题,每次用户答题完成、更新分数的同时,调用该方法生成新题目更新到state,即可实现答完一题自动刷新题目的效果。
  • 修正setState写法,不要直接修改旧状态对象,基于旧值计算后返回全新的状态对象即可。

修复后的核心代码参考:

class App extends Component {
  // 封装新题目生成逻辑
  generateQuestion = () => {
    const value1 = Math.floor(Math.random() * 100);
    const value2 = Math.floor(Math.random() * 100);
    const value3 = Math.floor(Math.random() * 100);
    return {
      value1,
      value2,
      value3,
      proposedAnswer: Math.floor(Math.random() * 3) + value1 + value2 + value3
    }
  }

  constructor(props) {
    super(props)
    this.state = {
      numQuestions: 0,
      numCorrect: 0,
      // 初始化生成第一题
      ...this.generateQuestion()
    }
  }

  rightanswer = () => {
    const { value1, value2, value3, proposedAnswer } = this.state;
    const isCorrect = proposedAnswer === value1 + value2 + value3;
    this.setState((oldstate) => ({
      numCorrect: isCorrect ? oldstate.numCorrect + 1 : oldstate.numCorrect,
      numQuestions: oldstate.numQuestions + 1,
      // 答完生成新题
      ...this.generateQuestion()
    }))
  }

  falseanswer = () => {
    const { value1, value2, value3, proposedAnswer } = this.state;
    const isCorrect = proposedAnswer !== value1 + value2 + value3;
    this.setState((oldstate) => ({
      numCorrect: isCorrect ? oldstate.numCorrect + 1 : oldstate.numCorrect,
      numQuestions: oldstate.numQuestions + 1,
      // 答完生成新题
      ...this.generateQuestion()
    }))
  }

  render() {
    // 取值从this.props改为this.state即可,其余JSX结构不变
    const { value1, value2, value3, proposedAnswer } = this.state;
    return (
      <div className="App">
        <div className="game">
          <h2>Mental Math</h2>
          <div className="equation">
            <p className="text">{`${value1} + ${value2} + ${value3} = ${proposedAnswer}`}</p>
          </div>
          <button onClick={() => this.rightanswer()}>True</button>
          <button onClick={() => this.falseanswer()}>False</button>
          <p className="text">
            Your Score: {this.state.numCorrect}/{this.state.numQuestions}
          </p>
        </div>
      </div>
    );
  }
}

export default App;

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.30 10:42:23