首页 > 解决方案 > 无线电输入在选择时重复(反应)

问题描述

我正在尝试制作一个对 codepen 做出反应的单题测验应用程序。我正在使用 api 来获取问题、3 个错误答案和问题的正确答案并将其添加到状态中。我在验证答案时遇到问题。单击 4 个选项之一后,我想有条件地渲染一个带有结果的 div。但问题是,在显示结果后,另一个无线电输入正在呈现。

const appRoot = document.getElementById('app');

class App extends React.Component{
  state={
    question:'',
    correct:'',
    incorrect:[],
    result: null
  }

componentDidMount(){
  axios.get('https://opentdb.com/api.php?amount=1&type=multiple')
  .then(res => {
    const data = res.data.results[0];
    const q = data.question;
    const correct = data.correct_answer;
    const incorrect = data.incorrect_answers;
    this.setState({question:q,correct:correct,incorrect:incorrect})
  })
}

evaluate(selected){
  if(selected === this.state.correct){
    this.setState({result: 'Correct!'})
  } else {
    this.setState({result:`Wrong! Correct Answer is ${this.state.correct}`})
  }
}

render(){
  const random = Math.floor(Math.random() * 3);
  const options = this.state.incorrect;
  options.splice(random, 0, this.state.correct);
  const choices = options.map((option,i) => (
    <div>
      <input type='radio' 
     name='option' 
     value={option} 
     key={i} onChange={() => this.evaluate(option)}/>
      <label for='option'>{option}</label>
    </div>
  ) )
  return(
    <div>
      <div>{this.state.question}</div>
      <div>{choices}</div>
      <div>{this.state.result}</div>
    </div>
  )
}
}

ReactDOM.render(<App />, appRoot)
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react-dom.min.js"></script>
<script src="https://unpkg.com/axios/dist/axios.min.js"></script>
<div id='app'></div>

标签: javascriptreactjs

解决方案


这似乎是一个诚实的错误(我一直有罪):

在你的render方法中,你改变你的数组:

const options = this.state.incorrect;
options.splice(random, 0, this.state.correct);

我怀疑你想要的是:

const options = this.state.incorrect.slice(); //create a COPY of the array
options.splice(random, 0, this.state.correct);

React 基本上是一个状态机,它查找状态的变化并智能地更新依赖于该状态的部分。但它只是 JavaScript。通过直接拼接状态对象,您正在更改渲染方法中的状态。React 不知道你改变了状态,因此,你最终会出现意想不到的行为——尤其render是经常被调用的行为。

我已经复制了您的代码段,以便您可以看到一个工作示例。

const appRoot = document.getElementById('app');

class App extends React.Component{
  state={
    question:'',
    correct:'',
    incorrect:[],
    result: null
  }

componentDidMount(){
  axios.get('https://opentdb.com/api.php?amount=1&type=multiple')
  .then(res => {
    const data = res.data.results[0];
    const q = data.question;
    const correct = data.correct_answer;
    const incorrect = data.incorrect_answers;
    this.setState({question:q,correct:correct,incorrect:incorrect})
  })
}

evaluate(selected){
  if(selected === this.state.correct){
    this.setState({result: 'Correct!'})
  } else {
    this.setState({result:`Wrong! Correct Answer is ${this.state.correct}`})
  }
}

render(){
  const random = Math.floor(Math.random() * 3);
  const options = this.state.incorrect.slice();
  options.splice(random, 0, this.state.correct);
  const choices = options.map((option,i) => (
    <div>
      <input type='radio' 
     name='option' 
     value={option} 
     key={i} onChange={() => this.evaluate(option)}/>
      <label for='option'>{option}</label>
    </div>
  ) )
  return(
    <div>
      <div>{this.state.question}</div>
      <div>{choices}</div>
      <div>{this.state.result}</div>
    </div>
  )
}
}

ReactDOM.render(<App />, appRoot)
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react-dom.min.js"></script>
<script src="https://unpkg.com/axios/dist/axios.min.js"></script>
<div id='app'></div>


推荐阅读