我如何在axios的反应中让我的测验问题及其在不同页面中的选择

时间:2018-07-14 12:42:14

标签: javascript reactjs axios

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

[
    {
        "_id":0,
        "name":"ANCY",
        "results":[
            {
                "subject":"maths",
                "score":1.46
            },
            {
                "subject":"english",
                "score":11.78
            },
            {
                "subject":"history",
                "score":6.67
            }
        ]
    },
    {
        "_id":1,
        "name":"Nancy",
        "results":[
            {
                "subject":"maths",
                "score":60.06
            },
            {
                "subject":"english",
                "score":52.79
            },
            {
                "subject":"history",
                "score":71.76
            }
        ]
    },
    {
        "_id":2,
        "name":"Peter",
        "results":[
            {
                "subject":"maths",
                "score":27.03
            },
            {
                "subject":"english",
                "score":6.30
            },
            {
                "subject":"history",
                "score":20.18
            }
        ]
    },
    {
        "_id":3,
        "name":"Harry",
        "results":[
            {
                "subject":"maths",
                "score":71.64
            },
            {
                "subject":"english",
                "score":24.80
            },
            {
                "subject":"history",
                "score":1.69
            }
        ]
    },
    {
        "_id":4,
        "name":"Paxy",
        "results":[
            {
                "subject":"maths",
                "score":28.68
            },
            {
                "subject":"english",
                "score":90.29
            },
            {
                "subject":"history",
                "score":34.41
            }
        ]
    }
]

2 个答案:

答案 0 :(得分:1)

页面并不完全不同,但是您可以使用一系列问题和答案来给出不同页面的错觉,但是所有页面都在同一组件中。一次只显示一个元素。例如,从您的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'
  },
]

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

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

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

questions的状态属性需要在componentDidMount中进行设置,到目前为止,代码中的这一部分看起来还不错。

我们将渲染部分设置为仅显示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道具并添加一个处理程序来使此单选按钮真正起作用。这就是我们的answers状态发挥作用的地方。 checked属性是一个布尔值,因此我们希望每当它们的当前值与answers数组位于相同的索引中时,都选中一个单选按钮。这就是我们的处理程序的外观:

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

    this.setState({answers}) 
  }

让我们更新渲染功能以合并checked属性和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-下一步,一旦阵列结束,您可能要禁用“下一步”按钮。当然,在实际的应用程序中,您将以不同的方式处理它,但是您需要确保不传递问题数组的大小。对于此示例,我们仅禁用“下一步”按钮,因此它将如下所示:

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

答案 1 :(得分:0)

看看这个例子:

https://codesandbox.io/s/km4538r82r

来自此库:

react-distributed-forms