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?
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?
- for one thing you don't want to name your class React. use something like class PanelContainer extends React.Component – brub Commented Jan 26, 2018 at 17:52
- Return just one element. Wrap it in a div or something. – Agney Commented Jan 26, 2018 at 17:58
6 Answers
Reset to default 9Here 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.
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>
);
- Dont name your class
React
- Unless you're using React 16 you need to wrap everything inside a div (on render method)
- You don't need
questionsMap
. You can just use the index thatmap
gives you for free, themap
function's first argument is the element, and the second will be the index. - Deconstruct your questions and answer inside render, before the return, like so: `const { questions, answers } = this.state; For readability.
- Goodluck
return
method expects only 1 child and in your example, it had 3 children ie:
- Intro component
- an array of
<Panel>
s - Result component.
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
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>
);
}
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 _.