5

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?

asked Jan 26, 2018 at 17:49
2
  • for one thing you don't want to name your class React. use something like class PanelContainer extends React.Component Commented Jan 26, 2018 at 17:52
  • Return just one element. Wrap it in a div or something. Commented Jan 26, 2018 at 17:58

6 Answers 6

9

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.

answered Jan 26, 2018 at 17:52
Sign up to request clarification or add additional context in comments.

5 Comments

Ahh this is a fantastic answer, thank you! For the record, I do not name my components 'React'. I quickly through together an example instead of using my rather verbose actual code, and that was a typo. But regardless, thank you!
I figured no worries!
Mark one of answers as correct so people don't keep answering ;), let me know if you have any other question or things you need me to clarify!
I'm trying to mark yours as correct, but SO is telling me my question hasn't been posted for long enough.
How can we access the props received in component <Panel /> on the basis of their index?
0

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>
);
answered Jan 26, 2018 at 17:56

Comments

0
  1. Dont name your class React
  2. Unless you're using React 16 you need to wrap everything inside a div (on render method)
  3. You don't need 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.
  4. Deconstruct your questions and answer inside render, before the return, like so: `const { questions, answers } = this.state; For readability.
  5. Goodluck
answered Jan 26, 2018 at 17:57

Comments

0

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

answered Oct 28, 2019 at 17:41

Comments

0

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> 
 );
 }
answered Jan 12, 2022 at 6:47

Comments

-1

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

answered Jan 26, 2018 at 17:56

Comments

Your Answer

Draft saved
Draft discarded

Sign up or log in

Sign up using Google
Sign up using Email and Password

Post as a guest

Required, but never shown

Post as a guest

Required, but never shown

By clicking "Post Your Answer", you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.