简体   繁体   中英

React conditional rendering of multiple child components

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>
)

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); 

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

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

You should wrap the JSX into a <div/>

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM