Reputation: 559
I have one component that I'm trying to render four times, each time with different props. To be a little more succinct with my code and not actually write out the JSX for the component and its props each time, I was trying to use map
to create different instances of the component. Right now, here's what that looks like:
import React, { Component } from 'react';
import Panel from './components/Panel';
import Results from './components/Results';
import Intro from './components/Intro';
const questionsMap = [0, 1, 2, 3];
class React extends Component {
constructor (props) {
super (props);
this.state = {
questions: ['question1', 'question2', 'question3', 'question4'],
answers: ['answers1', 'answers2', 'answers3', 'answers4']
}
this.onSelect = this.onSelect.bind(this);
}
onSelect(value) {
/* Some code for when buttons are clicked */
}
render () {
return (
<Intro />
{questionsMap.map(i => {
return <Panel question={this.state.questions.i} answers={this.state.answers.i} onSelect={this.onSelect} />
})}
<Results />
);
}
}
export default App;
Right now I'm getting an Unexpected token
error pointing to the line under my render that starts with {questionsMap.map()}
, aka the part where I'm trying to actually do the mapping I mentioned. I assume I'm using the wrong syntax to accomplish what I want?
Upvotes: 5
Views: 29656
Reputation: 446
the problem is that you are returning more than one element which is invalid in react if you want to return more than one element you can either wrap them inside a div which makes an extra element on the DOM or you can use React fragment
case 1:
render () {
return (
<> //<React.fragment //either you the empty tag or the one with React.fragment they are both are valid
<Intro />
{questionsMap.map((_,i) => {
return <Panel question={this.state.questions[i]} answers=
{this.state.answers[i]} onSelect={this.onSelect} />})}
<Results />
</> //</React.fragment>
);
}
case 2:
render () {
return (
<div>
<Intro />
{questionsMap.map((_,i) => {
return <Panel question={this.state.questions[i]} answers=
{this.state.answers[i]} onSelect={this.onSelect} />})}
<Results />
</div>
);
}
Upvotes: 0
Reputation: 53
return
method expects only 1 child and in your example, it had 3 children ie:
<Panel>
s to fix this, simplest way is to inclose within <div>...</div>
tags
or in the case where this extra div hinders with the styling, you can simply enclose within <>...</>
tags
Upvotes: 0
Reputation: 5146
Here is the correct syntax:
import React, { Component } from 'react';
import Panel from './components/Panel';
import Results from './components/Results';
import Intro from './components/Intro';
const questionsMap = [0, 1, 2, 3];
class React extends Component {
constructor (props) {
super (props);
this.state = {
questions: ['question1', 'question2', 'question3', 'question4'],
answers: ['answers1', 'answers2', 'answers3', 'answers4']
}
this.onSelect = this.onSelect.bind(this);
}
onSelect(value) {
/* Some code for when buttons are clicked */
}
render () {
return (
<div>
<Intro />
{questionsMap.map(i => {
return <Panel question={this.state.questions[i]} answers={this.state.answers[i]} onSelect={this.onSelect} />
})}
<Results />
</div>
);
}
}
export default App;
But there are a few things that are not exactly a good practice, I assume this is some sort of test so I don't expect that you will name one of your components React
.
On top of that you could simply map through the state, I would change the code a bit like this:
import React, { Component } from 'react'; import Panel from './components/Panel'; import Results from './components/Results'; import Intro from './components/Intro';
class React extends Component {
constructor (props) {
super (props);
this.state = {
questions: ['question1', 'question2', 'question3', 'question4'],
answers: ['answers1', 'answers2', 'answers3', 'answers4']
}
this.onSelect = this.onSelect.bind(this);
}
onSelect(value) {
/* Some code for when buttons are clicked */
}
render () {
return (
<div>
<Intro />
{this.state.questions.map((question, questionIndex) => {
return (<Panel
question={question}
answers={this.state.answers[questionIndex]}
onSelect={this.onSelect} />
)
})}
<Results />
</div>
);
} }
export default App;
Alternatively you could have an array of objects with a field named question and another named answer, just to give you another idea.
Upvotes: 9
Reputation: 621
React
questionsMap
. You can just use the index that map
gives you for free, the map
function's first argument is the element, and the second will be the index.Upvotes: 0
Reputation: 136
At first, render can return only one element. You should wrap your components with div
. At second, this.state.questions.i
is wrong syntax. Use this.state.questions[i]
.
Finally, I think there's the better approach:
return (
<div>
<Intro />
{
this.state.questions.map((question, i) => {
return <Panel question={question} answers={this.state.answers[i]} onSelect={this.onSelect} />
})
}
<Results />
</div>
);
Upvotes: 0
Reputation: 736
You haven't used the map function correctly.
Please check with the below code
import React, { Component } from 'react';
import Panel from './components/Panel';
import Results from './components/Results';
import Intro from './components/Intro';
const questionsMap = [0, 1, 2, 3];
class React extends Component {
constructor (props) {
super (props);
this.state = {
questions: ['question1', 'question2', 'question3', 'question4'],
answers: ['answers1', 'answers2', 'answers3', 'answers4']
}
this.onSelect = this.onSelect.bind(this);
}
onSelect(value) {
/* Some code for when buttons are clicked */
}
render () {
return (
<Intro />
{questionsMap.map((_,i) => {
return <Panel question={this.state.questions[i]} answers={this.state.answers[i]} onSelect={this.onSelect} />
})}
<Results />
);
}
}
export default App;
1st argument in map is the value and second argument is index. Since, we don't need value from map so I have given it as _.
Upvotes: -1