我对 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>;
}
}
最佳答案
页面并不完全不同,但您可以使用问题和答案数组来给出不同页面的错觉,但所有页面都在同一组件中。一次只显示一个元素。例如,假设您的获取请求中的 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: []
}
}
需要在 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
属性并添加一个处理程序来使这个单选输入按钮实际工作。这就是我们的 answers
状态发挥作用的地方。 checked
属性是一个 bool 值,因此我们希望只要单选按钮的当前值与 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>
关于javascript - 我怎样才能让我的每个测验问题及其在不同页面中的选择通过 axios 使用react,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/51338597/