7

Normally if you have something like:

<SomeComponent foo={bar} />

you can make it optional by using a ternary:

{bar ? <SomeComponent foo={bar} /> : null}

But what if the block you are starting with contains a component plus some text (a single space) and a variable, e.g.:

<SomeComponent foo={bar} /> {foobar}

Wrapping it in parentheses won't work:

{bar ? (<SomeComponent foo={bar} /> {foobar}) : null}

and in fact the only way I found to make it work was to wrap everything in another element:

{bar ? <span><SomeComponent foo={bar} /> {foobar}</span> : null}

Is there any other way to tell React that:

<SomeComponent foo={bar} /> {foobar}

is a discrete chunk, so that I can use it in a ternary (inside JS, not JSX, logic) ... without adding meaningless wrapper elements?

machineghost
  • 33,529
  • 30
  • 159
  • 234

2 Answers2

7

There used to be two suboptimal ways to achieve this:

  1. Using an array, which requires adding keys to React elements:

    {bar ? [<SomeComponent key="1" foo={bar} />, " ", foobar] : null}
    
  2. Creating a wrapper component, like @margaretkru suggested.

But with React 16.2.0+ you can use improved fragments:

{bar ? <React.Fragment><SomeComponent foo={bar} /> {foobar}</React.Fragment> : null}

or, even better, you can use the shorthand syntax:

{bar ? <><SomeComponent foo={bar} /> {foobar}</> : null}

Fragments won't produce an additional container element.

silvenon
  • 2,068
  • 15
  • 29
  • 2
    wow, that's cool. I thought you could only use fragments when returning from `render`, but now when I think about it, it shouldn't matter, it is all `jsx` anyway :) – margaretkru Jan 06 '18 at 23:44
  • 1
    Technically `<>` is still a wrapper, but since I suspect that a truly wrapper-less solution doesn't exist (and since it's not truly "meaningless", as it is defining a fragment), this seems like the best viable option ... and also, like @margaretkru said, it's pretty cool :) – machineghost Jan 07 '18 at 18:56
  • 1
    Yeah, it's semantically a wrapper, but doesn't render as one. I updated my answer for older React versions. @margaretkru I linked to your very elegant solution. :) – silvenon Jan 08 '18 at 23:59
2

You could define a small component that would act as a wrapper but won't render any markup, but it technically is still a wrapper. I use this approach by defining Aux component:

const Aux = (props) => (props.children);

Then you can do:

{bar ? <Aux><SomeComponent foo={bar} /> {foobar}</Aux> : null}

This at least avoids unnecessary markup in the resulting html which might be crucial for styling purposes, if you are using flex-box for example.

margaretkru
  • 2,751
  • 18
  • 20