簡體   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