28

I'm trying to render multiple child components depending on state however I'm only able to return one child component (SyntaxError: Adjacent JSX elements must be wrapped in an enclosing tag)

Each child component passes the same props, how could this code be kept DRY?

Works

export default ({changeState, myState, handleClick}) => ( <Navigation> <span>Navigation</span> <button onClick={() => changeState()}>Navigation</button> { myState ? <NavigationItem handleClick={handleClick} title={'#Link-1'} /> : null } </Navigation> ) 

Don't

export default ({changeState, myState, handleClick}) => ( <Navigation> <h1>Navigation</h1> <button onClick={() => changeState()}>Navigation</button> { myState ? <NavigationItem handleClick={handleClick} title={'#Link-1'} /> <NavigationItem handleClick={handleClick} title={'#Link-2'} /> <NavigationItem handleClick={handleClick} title={'#Link-3'} /> : null } </Navigation> ) 
0

2 Answers 2

52

Directly we can't return more than one elements.

Possible Solutions:

1- Either you need to wrap all the elements in a div or any other wrapper element.

2- We can return an array of multiple elements also, So put all the items in an array, and return the array.

Like this:

{myState ? [ <NavigationItem handleClick={handleClick} title={'#Link-1'} />, <NavigationItem handleClick={handleClick} title={'#Link-2'} />, <NavigationItem handleClick={handleClick} title={'#Link-3'} /> ] : null } 

Check this example:

let b = true ? [1,2,3,4]: null; console.log('b = ', b);

This will throw error:

let b = true? 1 2 3 4: null; console.log('b = ', b);

Sign up to request clarification or add additional context in comments.

1 Comment

Thanks, very handy with the {myState && ...} syntax.
21

You can also use <Fragment> from ReactJS: https://reactjs.org/docs/fragments.html

The problem about wrapping all the elements with a <div>, is that you are adding more elements to the DOM, and sometimes it's impossible (for example, when you are rendering a <td> or <tr> inside a <table>. So, here is where <Fragment> comes to help us.

Just wrap all those elements in a <Fragment> and it'll be enough. Meaning:

{ myState && <Fragment> <NavigationItem handleClick={handleClick} title={'#Link-1'} /> <NavigationItem handleClick={handleClick} title={'#Link-2'} /> <NavigationItem handleClick={handleClick} title={'#Link-3'} /> </Fragment> } 

Anyways, this another "Conditional Rendering" approach is better in "code readability" sense: https://medium.com/@BrodaNoel/conditional-rendering-in-react-and-jsx-the-solution-7c80beba1e36

It basically proposes the use of a <Conditional> element, like:

<Conditional if={myState}> <NavigationItem handleClick={handleClick} title={'#Link-1'} />, <NavigationItem handleClick={handleClick} title={'#Link-2'} />, <NavigationItem handleClick={handleClick} title={'#Link-3'} /> </Conditional> 

^ This looks better for my eyes :D

5 Comments

That Conditional component seems like an unnecessary abstraction that adds more boilerplate code :( I feel like people try too hard with their "smart abstractions". The reality is, people have no idea what your abstraction does, but most programmers know basic JS syntax... It gets worse when you move that code into a separate project and now people have to actually go into that project to see why its not working.
@Doug yes, I agree. I always use just the {!!var && <div />}. But some times (some teams) requires that EVERYTHING has to be declarative, thus they use this kind of behaviors. Sometimes they have to do it due to there are some dynamical code generation, and some other magics/yerbas.
Fragment's short syntax makes code more readable. However, not all tools support it.
@Sourabh Yeap. Even Github breaks all the colors when there is a short syntax of Fragment.
I think the <Conditional> component concept is a good one. React should have something like this out of the box like Vue.js does.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.