2

I want to have a dynamic rendering of JSX as below;

<ColumnLayout container spacing={1}>
    <ColumnLayout item xs={9}>                    
        <b>{text}</b>
    </ColumnLayout>
    {showSubTextAndIcon ?
        <ColumnLayout item xs={2}>                    
            <span>{subText}</span>
        </ColumnLayout>
        <ColumnLayout item xs={1}>
            <Icon  />
        </ColumnLayout>
        : null
    }
</ColumnLayout>

Thus, I want that only if "showSubTextAndIcon" is true, then render the subtext and Icon. Now the above does not work and I get a syntax error saying;

Adjacent JSX elements must be wrapped in an enclosing tag. Did you want a JSX fragment <>...</>

This works if I add a wrapping ColumnLayout. However, that messes my layout when showSubTextAndIcon is true.

{showSubTextAndIcon ?
        <ColumnLayout container spacing={1}>
            <ColumnLayout item xs={2}>                    
                <span>{subText}</span>
            </ColumnLayout>
            <ColumnLayout item xs={1}>
                <Icon  />
            </ColumnLayout>
        </ColumnLayout>
        : null
    }

Note: ColumnLayout is derived from material ui library.

halfer
  • 19,824
  • 17
  • 99
  • 186
copenndthagen
  • 49,230
  • 102
  • 290
  • 442

4 Answers4

2

All you need is Fragment, as React is expecting an array or an element as a return:

import React, { Fragment } from 'react';

and just wrap it.


{showSubTextAndIcon &&
       <Fragment>
          <ColumnLayout item xs={2}>                    
              <span>{subText}</span>
          </ColumnLayout>
          <ColumnLayout item xs={1}>
              <Icon  />
          </ColumnLayout>
        </Fragment>
    }
I am L
  • 4,288
  • 6
  • 32
  • 49
  • You can also omit `Fragment` and just use `<> >` – Murat Karagöz Jun 07 '21 at 08:01
  • You can also do that ^^, but take note that it only works if you are using Babel v7.0.0-beta.31 & above. (In create react app its already working in the newer versions). Also take note that you cant pass attributes on the shorthand but you can on the longhand. So you might also consider that if you are mapping it. – I am L Jun 07 '21 at 08:06
1

If you want a single condition, you need to wrap your elements, as the error suggests and as you have discovered already. If it breaks your layout, you can either change your CSS, either try with a simple <div> instead of nesting ColumnLayout elements.

Another solution would be adding the same condition to each of the elements you want to show under that condition, like:

<ColumnLayout container spacing={1}>
    <ColumnLayout item xs={9}>                    
        <b>{text}</b>
    </ColumnLayout>
    {showSubTextAndIcon &&
        <ColumnLayout item xs={2}>                    
            <span>{subText}</span>
        </ColumnLayout>}
    {showSubTextAndIcon &&
        <ColumnLayout item xs={1}>
            <Icon  />
        </ColumnLayout>}
</ColumnLayout>
freesoul
  • 528
  • 5
  • 14
1

An alternative way of doing it is to wrap components in an array and give them keys:

<ColumnLayout container spacing={1}>
    <ColumnLayout item xs={9}>                    
        <b>{text}</b>
    </ColumnLayout>
    {showSubTextAndIcon && [
        <ColumnLayout item xs={2} key={1}>                    
            <span>{subText}</span>
        </ColumnLayout>,
        <ColumnLayout item xs={1} key={2}>
            <Icon  />
        </ColumnLayout>
    ]}
</ColumnLayout>
Simone
  • 20,302
  • 14
  • 79
  • 103
0

You need to enclose it in a fragment as react expects only one element as return:

<ColumnLayout container spacing={1}>
    <ColumnLayout item xs={9}>                    
        <b>{text}</b>
    </ColumnLayout>
    {showSubTextAndIcon ?
       <>
        <ColumnLayout item xs={2}>                    
            <span>{subText}</span>
        </ColumnLayout>
        <ColumnLayout item xs={1}>
            <Icon  />
        </ColumnLayout>
       </>
        :" "
    }
</ColumnLayout>
Noel
  • 88
  • 7