我对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
}
]
}
]
答案 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)