107

I wanted to know if its possible to do nested if else if in ReactJS JSX?

I have tried various different ways and I am unable to get it to work.

I am looking for

if (x) {
  loading screen
} else {
  if (y) {
    possible title if we need it
  }
  main 
}

I have tried this but I can not get it to render. I have tried various ways. It always breaks once I add the nested if.

{
  this.state.loadingPage ? (
    <div>loading page</div>
  ) : (
    <div>
      this.otherCondition && <div>title</div>
      <div>body</div>
    </div>
  );
}

Update

I ended up choosing the solution to move this to renderContent and call the function. Both of the answers did work though. I think I may use the inline solution if it is for a simple render and renderContent for more complicated cases.

Thank you

Penny Liu
  • 15,447
  • 5
  • 79
  • 98
ALM
  • 2,555
  • 7
  • 31
  • 45
  • 1
    just fyi `if`/`else` constructs aren't "loops" – Pointy May 19 '16 at 00:34
  • The `(
    body
    )` part doesn't seem to belong to anything. That's an error. Otherwise what you have seems fine.
    – Felix Kling May 19 '16 at 00:43
  • @FelixKling If I do it as
    body
    it will not work. The point is I want to have some data in the else that is always shown and another if for the title.
    – ALM May 19 '16 at 00:49
  • I understand, but `foo ? bar : baz abc` is not valid JavaScript. You want `
    {this.state.someBoolean ? ... : ...}
    body
    ` then.
    – Felix Kling May 19 '16 at 00:52
  • You cannot have two *expressions* after each other: `4 5` is simply invalid. That's not a problem for statements. – Felix Kling May 19 '16 at 00:59
  • Maybe that's your confusion: `foo ? bar : baz abc` is interpreted as `(foo ? bar : baz) (abc)` **not** as `foo ? bar : (baz abc)`. But both are invalid anyway. – Felix Kling May 19 '16 at 01:05
  • Re *"Updated as solution below but this will still not render."* I missed `{...}` in my code, you can see the updated version in my code. Also please don't don't change your original question, because my answer doesn't make sense now anymore (I rolled back your edit). – Felix Kling May 19 '16 at 01:06
  • The original code is not the issue, the problem is I still do not see how to nest another condition within the initial if (X) ? a : b ( nested if (y) (title) main) – ALM May 19 '16 at 01:22

6 Answers6

189

You need to wrap your title and body in a container. That could be a div. If you use a fragment instead, you'll have one less element in the dom.

{ this.state.loadingPage
  ? <span className="sr-only">Loading... Registered Devices</span>
  : <>
      {this.state.someBoolean
        ? <div>some title</div>
        : null
      }
      <div>body</div>
    </>
}

I would advise against nesting ternary statements because it's hard to read. Sometimes it's more elegant to "return early" than to use a ternary. Also, you can use isBool && component if you only want the true part of the ternary.

renderContent() {
  if (this.state.loadingPage) {
    return <span className="sr-only">Loading... Registered Devices</span>;
  }

  return (
    <>
      {this.state.someBoolean && <div>some title</div>}
      <div>body</div>
    </>
  );
}

render() {
  return <div className="outer-wrapper">{ this.renderContent() }</div>;
}

Caveat to the syntax someBoolean && "stuff": if by mistake, someBoolean is set to 0 or NaN, that Number will be rendered to the DOM. So if the "boolean" might be a falsy Number, it's safer to use (someBoolean ? "stuff" : null).

Neal Ehardt
  • 10,334
  • 9
  • 41
  • 51
59

Instead of nesting ternary operators as it is often suggested or creating a separate function that will not be reused anywhere else, you can simply call an inline expression:

<div className="some-container">
{
   (() => {
       if (conditionOne)
          return <span>One</span>
       if (conditionTwo)
          return <span>Two</span>
       else (conditionOne)
          return <span>Three</span>
   })()
}
</div>
dehumanizer
  • 1,250
  • 12
  • 15
  • 6
    "prettiest" solution in here but from a performance perspective, this will add some overhead since an IIFE is created every time a render gets invoked. – dipole_moment Nov 30 '18 at 21:47
  • 2
    If you need a conditional rendering, it doesn't really matter wether it's IIFE or nested ternaries (which I grew to like since posting my original answer), or `R.cond([...])`. If anything, the "bigger" performance impact is the inline function creation. But in the big picture, it's a premature performance optimization and you'd be better off using PureComponent or ShouldComponentUpdate. My answer differs from the accepted answer mostly in the fact that you don't have to create a class member function that you won't use anywhere else and can just do it inline. – dehumanizer Dec 01 '18 at 22:44
  • @dehumanizer your's solution worked for me. Thank you so much . More power to you :) – Md Noorshid Sep 28 '22 at 07:43
20

You can check multiple conditions to render components accordingly like below:

  this.state.route === 'projects'
  ? 
  <div> <Navigation onRouteChange={this.onRouteChange}/> Projects</div>
  :
  this.state.route === 'about'
  ?
  <div> <Navigation onRouteChange={this.onRouteChange}/> About</div>
  :
  this.state.route === 'contact'
  ?
  <div> <Navigation onRouteChange={this.onRouteChange}/> Contact</div>
  :
  <p> default </p>
Akshata Dabade
  • 477
  • 5
  • 10
19

You can nest as many statements as possible. please follow this code assuming that this.state.firstTestValue, this.state.someTestValue and this.state.thirdValueTest are your test values from the state.

{this.state.firstTestValue
    ? <div >First Title</div>
    : [
        this.state.someTestValue
            ? <div>Second Title</div>
            : [
                this.state.thirdValueTest 
                ? <div>Some Third Title</div> 
                : <div>Last Title</div>
            ]
    ]
}
Penny Liu
  • 15,447
  • 5
  • 79
  • 98
Bryan Austin
  • 309
  • 2
  • 11
7

Your code in the alternative is not valid JavaScript/JSX expression:

(
  this.state.someBoolean ?
  (<div>some title</div>):(<div>some other title</div>)
  <div>body</div>
)

Lets simplify this to

(
  true ? 42 : 21
  3
)

This throws the error

Uncaught SyntaxError: Unexpected number(…)

You cannot just have two expression next to each other.

Instead you have to return a single value from the false branch of the conditional operator. You can do this by simply putting it in another JSX element:

(
  <div>
    {this.state.someBoolean ? (<div>some title</div>) : (<div>some other title</div>)}
    <div>body</div>
  </div>
)

If you want to only show "body" when "some other title" is shown, you need to move <div>body</div> into the false branch of the conditional operator:

(
  this.state.someBoolean ?
    (<div>some title</div>) :
    (<div>
       <div>some other title</div>
       <div>body</div>
    </div>)
)

Or maybe you want

(
  <div>
    {this.state.someBoolean ? (<div>some title</div>) : null}
    <div>body</body>
  </div>
)
Felix Kling
  • 795,719
  • 175
  • 1,089
  • 1,143
  • The problem is that I only want body to show up in some other title. Using "body" might not have been the best choice. I can rewrite – ALM May 19 '16 at 01:00
  • Then your original code makes even less sense and doesn't mat your `if...else` example.What you want is `this.state.someBoolean ? (
    some title
    ):(
    some other title
    body
    )` then.
    – Felix Kling May 19 '16 at 01:01
  • The thing is that I only want to show the title if another condition is true. The body will be shown as you have in the second example in the else section but then I need ANOTHER conditional on the title. The page shows either, A loading page OR a main page with or without a title – ALM May 19 '16 at 01:08
  • I updated my question with your example plus the additional conditional – ALM May 19 '16 at 01:13
  • Updated my answer. Note that all the examples only show the false branch of the outer conditional, because that's the only thing that was incorrect. If this is still not what you want, I really have no idea what you are talking about. – Felix Kling May 19 '16 at 01:16
  • Let us [continue this discussion in chat](http://chat.stackoverflow.com/rooms/112340/discussion-between-alm-and-felix-kling). – ALM May 19 '16 at 01:16
  • I updated the question to include what I originally asked about how to put a nested conditional inside another conditional. I would like to display a loading page or main page but in the main page it needs a condition on if it has a title, hence the nested conditional. I updated your solution with the additional condition . – ALM May 19 '16 at 01:20
  • So you already have the outer conditional, `{a ? b : c}`. You simply take my last example and replace `c` with it. As I said, only the false branch of the outer conditional is incorrect. Your outer conditional is fine and hence I haven't repeated it. Or in more concrete terms: Replace the line `this.otherCondition &&
    title
    ` in your updated example with `{this.state.someBoolean ? (
    some title
    ) : null}` from my example.
    – Felix Kling May 19 '16 at 01:26
  • Thank you for your help. In the end it turns out I had something else causing the runtime error. I made the changes you selected and it works. – ALM May 19 '16 at 02:25
0

As the other answer suggest, there are various ways to do a nested if else in react. Which one to use depends on situation and preferences.

In my opinion, for best code readability, on this occassion it'd be best to move the content of else to separate function:

renderContent() {
     return (
         <div>
             { this.otherCondition && <div>title</div> }
             <div>body</div>
         </div>
     );
}

render() {
    return (
        <div>
            { ... }
            {
                this.state.loadingPage ?
                    <div>loading page</div>
                    :
                    this.renderContent()
            }
            { ... }
        </div>
    )
}

Or if it's simple enough (in case no other elements are rendered), I'd go with:

render() {
    if (this.state.loadingPage) {
        return (
            <div>loading page</div>
        )
    }
    return (
        <div>
            { this.otherCondition && <div>title</div> }
            <div>body</div>
        </div>
    );
}

Here's an article on conditional rendering in React, so please check it out if you're interested in more details on this topic.

Nesha Zoric
  • 6,218
  • 42
  • 34