繁体   English   中英

我怎样才能在 axios 的反应中让我的每个测验问题及其在不同页面中的选择

[英]How can I have each of my my quiz questions and their choices in different pages in react by axios

我对 React 很陌生。 我正在准备测验。 我在同一页面上有我的问题和他们的选择。 我想要的是在不同的页面中让每个问题都有自己的选择。 单击按钮选择一个选项后,我想转到下一页的问题。 我怎样才能做到这一点?

import React from "react";
import axios from "axios";

function Question(props) {
  this.state = { questionNumber: 0 };
  let style = {
    margin: "5px"
  };
  clickHandler = () => {};

  return (
    <div className="Question">
      <h4>{props.question}</h4>
      <ul>
        {props.choices.map((c, i) => (
          <button style={style} clickHandler={this.clickHandler}>
            {c.choice}
          </button>
        ))}
      </ul>
    </div>
  );
}

class QuizApp extends React.Component {
  constructor(props) {
    super(props);
    this.state = { questions: [], choices: [] };
  }

  componentDidMount() {
    axios
      .get(
        "https://private-anon-c06008d89c-quizmasters.apiary-mock.com/questions"
      )
      .then(response => {
        this.setState({ questions: response.data });
      });
  }

  render() {
    return <div>{this.state.questions.map(q => new Question(q))}</div>;
  }
}

不是完全不同的页面,但您可以使用一系列问题和答案来提供不同页面的错觉,但都在同一个组件中。 一次只显示一个元素。 例如,假设您的 get 请求中的response.data如下:

[
  {
    question: 'What is question 1?',
    option1: 'Option 1',
    option2: 'Option 2',
    option3: 'Option 3'
  },
  {
    question: 'What is question 2?',
    option1: 'Option 1',
    option2: 'Option 2',
    option3: 'Option 3'
  },
  {
    question: 'What is question 3?',
    option1: 'Option 1',
    option2: 'Option 2',
    option3: 'Option 3'
  },
]

您希望每次都显示该 arrat 的一个索引,因此您需要另一个名为currentQuestionIndex状态属性。 从 0 开始,以便它可以从该数组的第一个问题开始。

您还需要在某个地方存储您的答案,因此,我们将添加一个answers状态属性。 这两个都应该在构造函数中定义,现在看起来像这样:

  constructor (props, context) {
    super(props, context)
    this.state = {
      currentQuestionIndex: 0,
      questions: [],
      answers: []
    }
  }

需要在您的componentDidMount设置questions状态属性,以便您的代码中的部分到目前为止看起来不错。

我们设置了渲染部分,以便它只显示currentQuestionIndex上的任何问题。 我还将添加“下一步”按钮,以便您可以导航到下一个问题。

它应该是这样的:

  render() {
    const { questions, currentQuestionIndex, answers } = this.state

    const { question, option1, option2, option3} = questions[currentQuestionIndex]

    return (<div>
        <h4>{question}</h4>

          <label>
            <input type='radio'
              value={option1}/>
            {option1}
          </label>
        <br/>

          <label>
            <input type='radio'
              value={option2}/>
            {option2}
          </label>
          <br/>
          <label>
            <input type='radio'
              value={option3}/>
            {option3}
          </label>
        <hr/>
        <button>Next</button>
      </div>);
  }

凉爽的! 现在我们需要通过添加checked prop并添加处理程序来使这个单选输入按钮实际工作。 这就是我们的answers状态发挥作用的地方。 checked道具是一个布尔值,所以我们想要一个单选按钮,只要它们的当前值与它们在answers数组中的索引相同,就会被检查。 所以这就是我们的处理程序的样子:

onChangeOption (value) {
    const { currentQuestionIndex } = this.state
    let answers = [...this.state.answers]
    answers[currentQuestionIndex] = value

    this.setState({answers}) 
  }

让我们更新我们的渲染函数以合并checked prop 和onChangeOption函数:

  render() {
    const { questions, currentQuestionIndex, answers } = this.state

    const { question, option1, option2, option3} = questions[currentQuestionIndex]

    return (<div>
        <h1>Question {currentQuestionIndex + 1}</h1>
        <h4>{question}</h4>

          <label>
            <input type='radio'
              checked={answers[currentQuestionIndex] === option1}
              value={option1}
              onChange={(evt) => this.onChangeOption(evt.target.value)}/>
            {option1}
          </label>
        <br/>

          <label>
            <input type='radio'
              checked={answers[currentQuestionIndex] === option2}
              value={option2}
              onChange={(evt) => this.onChangeOption(evt.target.value)}/>
            {option2}
          </label>
          <br/>
          <label>
            <input type='radio'
              checked={answers[currentQuestionIndex] === option3}
              value={option3}
              onChange={(evt) => this.onChangeOption(evt.target.value)}/>
            {option3}
          </label>
        <hr/>
        <button>Next</button>
      </div>);
  }

这应该照顾我们在该页面中的问题处理。 但是我们应该如何更改页面呢? 让我们处理下一个按钮,好吗?

如前所述,定义显示的问题是通过使用currentQuestionIndex的索引,因此在单击下一个按钮时,让我们增加它。 这是 onClick 处理程序:

  handleNext () {
     let incrementCurrentQuestionIndex = this.state.currentQuestionIndex + 1
     this.setState({currentQuestionIndex: incrementCurrentQuestionIndex})
  }

这是下一个按钮的样子:

<button onClick={() => this.handleNext()}>Next</button>

最后,让我们添加一些最后的修饰,以便这个小应用程序能够正常运行:

1- 由于您只收到有关componentDidMount生命周期方法的问题,因此您需要在问题仍在加载时添加占位符。 所以在render()方法中,在呈现你的问题之前,你想检查一下questions状态是否已经填写。像这样:

render() {
    const { questions, currentQuestionIndex, answers } = this.state

    // Will be rendered before you grab all your questions
    if (!questions.length) {
      return <div> Loading questions...</div>
    }

    // Do the rest...
  }

2-接下来,一旦您的阵列结束,您可能想要禁用“下一步”按钮。 当然,在您的实际应用程序中,您会以不同的方式处理它,但您需要确保不传递问题数组的大小。 在这个例子中,我们只是禁用了 Next 按钮,所以它看起来像这样:

 <button disabled={currentQuestionIndex === questions.length - 1} onClick={() => this.handleNext()}>Next</button>

更新:这有一个尴尬的流程,所以对于这个例子,当你用完问题时,最好只显示一个不同的页面。 为此,在您的render()函数上,只需添加一个条件,如果 currentQuestionIndex 较大或已达到问题数组的大小,则该条件显示测验已结束。 所以在你的问题被呈现之前是这样的:

if (currentQuestionIndex >= questions.length) {
      return (
        <div>
          <h3>End of the Quiz!</h3>
        </div>
      )
    }

示例应用程序也已相应更新。

tl;dr:利用你得到的一系列问题。 仅显示您所在的当前索引的问题和选项。 当您想继续下一个时,只需单击按钮增加当前索引。

这是功能齐全的示例应用程序:

 //Simulating data coming from axios const questionsArray = [ { question: 'What is question 1?', option1: 'Option 1', option2: 'Option 2', option3: 'Option 3' }, { question: 'What is question 2?', option1: 'Option 1', option2: 'Option 2', option3: 'Option 3' }, { question: 'What is question 3?', option1: 'Option 1', option2: 'Option 2', option3: 'Option 3' }, ] class App extends React.Component { constructor (props, context) { super(props, context) this.state = { currentQuestionIndex: 0, questions: [], answers: [] } } componentDidMount() { // Do your axios call and set the questions state. // For the sake of simplicity,I'll be using my array. this.setState({questions: questionsArray}) } handleNext () { let incrementCurrentQuestionIndex = this.state.currentQuestionIndex + 1 this.setState({currentQuestionIndex: incrementCurrentQuestionIndex}) } onChangeOption (value) { const { currentQuestionIndex } = this.state let answers = [...this.state.answers] answers[currentQuestionIndex] = value this.setState({answers}) } render() { const { questions, currentQuestionIndex, answers } = this.state if (!questions.length) { return <div> Loading questions...</div> } if (currentQuestionIndex >= questions.length) { return ( <div> <h3>End of the Quiz!</h3> </div> ) } const { question, option1, option2, option3} = questions[currentQuestionIndex] return (<div> <h1>Question {currentQuestionIndex + 1}</h1> <h4>{question}</h4> <label> <input type='radio' checked={answers[currentQuestionIndex] === option1} value={option1} onChange={(evt) => this.onChangeOption(evt.target.value)}/> {option1} </label> <br/> <label> <input type='radio' checked={answers[currentQuestionIndex] === option2} value={option2} onChange={(evt) => this.onChangeOption(evt.target.value)}/> {option2} </label> <br/> <label> <input type='radio' checked={answers[currentQuestionIndex] === option3} value={option3} onChange={(evt) => this.onChangeOption(evt.target.value)}/> {option3} </label> <hr/> <button onClick={() => this.handleNext()}>Next</button> </div>); } } ReactDOM.render( <App />, document.getElementById('app') );
 <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> <div id="app"></div>

看看这个例子:

https://codesandbox.io/s/km4538r82r

从这个库:

反应分布形式

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM