随机化从rest-API获取的测验答案

时间:2019-06-07 20:50:44

标签: arrays json reactjs

因此,我创建了一个测验应用程序,该应用程序可提取10个随机问题,其中三个不正确,一个正确答案可供选择。目前一切工作正常,除了我无法随机弹出答案。而且,我的意思是正确的答案始终位于提出的选择的底部。

我知道答案是Math.floor(Math.random()* ...),但老实说,我不知道将其放在哪里。我已经尝试了一切。我真的可以帮忙。

import React, { Component } from "react";
import "./App.css";

const API =
  "https://opentdb.com/api.php?amount=10&category=20&difficulty=medium";

class App extends Component {
  constructor(props) {
    super(props);
    this.state = {
      results: [],
      score: []
    };
  }

  componentDidMount() {
    this.populateAppWithData();
  }

  populateAppWithData() {
    fetch(API)
      .then(response => response.json())
      .then(data => this.setState({ results: data.results }))
      .catch(error => console.error(error))
  }

  render() {
    const { results } = this.state;
    return (
      <div className="App">
        <h1>Quiz App</h1>
        <TheCounter results={results}
          Counter={this.state.score}
        />
      </div>
    );
  }
}
class MythologyAnswers extends Component {
  constructor(props) {
    super(props);
    this.state = {
      answered: "",
      isRight: null,
    };
  }
  answerClicked(answer) {
    const { hasAnswered, correct_answer } = this.props;
    return event => {
      const isRight = correct_answer === answer;
      hasAnswered(isRight);
      this.setState({
        answered: answer,
        isRight,
      });
    };
  }

  render() {
    const { question, correct_answer, incorrect_answers } = this.props;
    const { answered, isRight } = this.state;
    return (
      <div className="allAnswers">
        {question}
        {incorrect_answers && incorrect_answers
          .concat(correct_answer)
          .map(answer => (<div onClick={this.answerClicked(answer)}>{answer} </div>))}<br />
        {answered && `You answered ${answered}`} {" "} <br />
        <div className="correctAnswer"> {" "}{answered && isRight && "This is correct!"} </div> <br />
        <div className="incorrectAnswer"> {" "}{answered && !isRight && `This is incorrect. The correct answer is ${this.props.correct_answer}`} {" "}</div>
      </div>
    )
  }
}
class TheCounter extends Component {
  constructor(props) {
    super(props);
    this.state = {
      right: 0,
      Counter: 0,
      unanswered: 0,
    };
  }
  questionAnswered = isRight => {
    this.setState(({ Counter, right }) => ({
      Counter: Counter + 1,
      right: right + isRight,
    }));
  }
  render() {
    const { results } = this.props;
    const { Counter } = this.state;
    const unanswered = this.props.results && Counter;
    if (unanswered >= 10) {
      return <div className="theUnanswered"> You got {this.state.right} right out of {this.state.Counter} </div>;
    }
    const question = results[Counter];
    return (
      <div className="newQuestion">
        <MythologyAnswers {...question} hasAnswered={this.questionAnswered} />
      </div>
    )
  }
}
export default App;

4 个答案:

答案 0 :(得分:1)

我们只需要在正确的位置应用随机化器即可。您使用.concat()合并两个数组,因此在调用.map()

之后和之后使用随机化器是很有意义的。

我已经设置了一些可以保留您已经编写的现有逻辑的东西。

这将有助于创建新的Arr并设置组件的标记。

  renderChoices = () => {
    const { correct_answer, incorrect_answers } = this.props;

    let allAnswers = incorrect_answers
      ? incorrect_answers.concat(correct_answer)
      : [];

    //simple shuffle algorithm. Just inject your array and it'll pop out a new one.

    function createRandom(arr) {
       let myArr = [...arr];  //copy arr we pass in
       let randomizedArr = []; //gets popuated by loop

       while (myArr.length > 0) {
          var randomIndex = Math.floor(Math.random() * myArr.length); //create random number
          randomizedArr.push(myArr[randomIndex]); //add choice randomly to arr
          myArr.splice(randomIndex, 1); //cut out a piece of the array then resart loop
      }
       //when loop has finished, return random array
       return randomizedArr;
    }

    //call randomizer and get new Arr
    let randomizedArr = createRandom(allAnswers); 

    //use .map to create markup with randomizedArr
    return randomizedArr.map(answer => {
      return <div onClick={this.answerClicked(answer)}>{answer}</div>;
    });
  };

因此,如果您要在render中调用上述函数,它将为您创建答案集。

  render() {
    const { question } = this.props;
    const { answered, isRight } = this.state;
    return (
      <div className="allAnswers">

        {question}

        { this.renderChoices()}

        <br />

        {answered && `You answered ${answered}`} <br />

        <div className="correctAnswer">
          {answered && isRight && "This is correct!"}
        </div>

        <br />

        <div className="incorrectAnswer">
          {answered &&
            !isRight &&
            `This is incorrect. The correct answer is ${
              this.props.correct_answer
            }`}
        </div>
      </div>
    );
  }

清洁而不是太复杂:)

编辑:因此无需过多更改原始代码:

  createRandom(arr) {
    let myArr = [...arr]; //copy arr we pass in
    let randomizedArr = []; //gets popuated by loop

    while (myArr.length > 0) {
      var randomIndex = Math.floor(Math.random() * myArr.length); //create random number
      randomizedArr.push(myArr[randomIndex]); //add choice randomly to arr
      myArr.splice(randomIndex, 1); //cut out a piece of the array then resart loop
    }
    //when loop has finished, return random array
    return randomizedArr;
  }

  render() {
    const { question, correct_answer, incorrect_answers } = this.props;
    const { answered, isRight } = this.state;
    const allAnswers =
      incorrect_answers ? incorrect_answers.concat(correct_answer) : [];
    const randomizedAnswers = this.createRandom(allAnswers)

    return (
      <div className="allAnswers">
        {question}
        {randomizedAnswers
            .map(answer => (
              <div onClick={this.answerClicked(answer)}>{answer} </div>
            ))}
        <br />
        {answered && `You answered ${answered}`} <br />
        <div className="correctAnswer">
          {answered && isRight && "This is correct!"}
        </div>
        <br />
        <div className="incorrectAnswer">

          {answered &&
            !isRight &&
            `This is incorrect. The correct answer is ${
              this.props.correct_answer
            }`}
        </div>
      </div>
    );
  }

因此,在编辑后的版本中,我们做了几件事:

  1. 定义了一个名为createRandom()的函数...它所做的只是 随机选择答案。
  2. render中,我们创建了一个名为allAnswers的新变量, concat() incorrect_answerscorrect_answer就像您一样 先前。如果没有定义incorrect_answers,我们将使用 空数组[]作为默认值。
  3. 创建一个名为randomizedAnswers的新变量。我们称之为 createRandom()并传入allAnswers作为参数。它返回 供我们使用的随机数组。
  4. 然后在.map()上方randomizedAnswers创建您的 答案选择标记。

答案 1 :(得分:0)

我将在获取数据后立即添加它。使用像Fisher-Yales这样的内联shuffle,您根本不需要修改结构。

const fisherYalesShuffle = (a) => {
    let j, x, i;
    for (i = a.length - 1; i > 0; i--) {
        j = Math.floor(Math.random() * (i + 1));
        x = a[i];
        a[i] = a[j];
        a[j] = x;
    }
}

但是,由于您通常希望将尽可能多的数据逻辑移至后端,因此您也应该考虑将其改组到那里。

答案 2 :(得分:0)

在下面的代码中,我想您正在尝试使用正确的答案连接错误的答案

incorrect_answers && incorrect_answers
          .concat(correct_answer)

因此数组变为[incorrect_answers,incorrect_answers,incorrect_answers,correct_answer] 即正确答案在结尾 因此,如果您想在随机位置插入正确答案并假设有4个选项,则首先生成一个介于0到3之间的随机数

let randonIndex = Math.floor(Math.random() * 4)

然后在随机索引处插入正确答案

incorrect_answers && incorrect_answers
          .splice(randomIndex, 0, correct_answer);

答案 3 :(得分:0)

您可以定义一个随机播放功能(这是Fisher-Yates(又名Knuth)随机播放):

function shuffle(array) {
  var currentIndex = array.length, temporaryValue, randomIndex;

  // While there remain elements to shuffle...
  while (0 !== currentIndex) {

    // Pick a remaining element...
    randomIndex = Math.floor(Math.random() * currentIndex);
    currentIndex -= 1;

    // And swap it with the current element.
    temporaryValue = array[currentIndex];
    array[currentIndex] = array[randomIndex];
    array[randomIndex] = temporaryValue;
  }

  return array;
}

然后在设置状态时仅应用该功能:

this.setState({ results: this.shuffle(data.results) })