20

I want to write the equivalent in react:

if (this.props.conditionA) {
    <span>Condition A</span>
} else if (this.props.conditionB) {
    <span>Condition B</span>
} else {
    <span>Neither</span>
}

So maybe

render() {
    return (<div>
        {(function(){
            if (this.props.conditionA) {
                return <span>Condition A</span>
            } else if (this.props.conditionB) {
                return <span>Condition B</span>
            } else {
                return <span>Neither</span>
            }
        }).call(this)}
    </div>)
}

But that seems overly complex. Is there a better way?

Henry
  • 5,943
  • 1
  • 19
  • 30

6 Answers6

71

Why do you say that the ternary is not expressive enough?

render() {
  return <span>
    {this.props.conditionA ? "Condition A" 
      : this.props.conditionB ? "Condition B" 
      : "Neither"}
  </span>;
}
Yosef Weiner
  • 4,522
  • 22
  • 35
  • 2
    Yeah good point, this is actually pretty tidy. I've used the ternary expression (in jsx) but started to find it cumbersome, maybe I need a better example before I can explain why. – Henry Aug 07 '16 at 05:25
  • This is a bad practice, nesting ternary operators can quickly become unreadable: https://eslint.org/docs/rules/no-nested-ternary – SherloxTV Jun 18 '18 at 08:59
  • @SherloxFR That is debatable https://github.com/eslint/eslint/issues/3480#issuecomment-189960121 – Yosef Weiner Jun 18 '18 at 10:48
  • @YosefWeiner _I think_ it's actually better to make two {} blocks with ternary (or just &&), even if some people are not able to find a way around it, it is possible and from far more readable, the readability of a code isn't something debatable, even if I understand some people can struggle finding solutions to this eslint rule. – SherloxTV Jun 19 '18 at 10:26
  • Wouldn't this give no-nested-ternary in lint? – Swapnil B. Aug 06 '19 at 15:39
  • @SwapnilB. Look at the comments above – Yosef Weiner Aug 06 '19 at 15:44
  • aha. i missed that comment. Sorry for the trouble. – Swapnil B. Aug 07 '19 at 16:25
9

If you don't need the <div>, just return the <span> elements:

render() {
  if (this.props.conditionA) {
    return <span>Condition A</span>;
  } else if (this.props.conditionB) {
    return <span>Condition B</span>;
  } else {
    return <span>Neither</span>;
  }
}

You can even move the last return statement out of the else block.


In general, you don't have to embed everything inside JSX. It's perfectly fine to compute values beforehand, just like you do elsewhere:

render() {
  let content;
  if (this.props.conditionA) {
    content = <span>Condition A</span>;
  } else if (this.props.conditionB) {
    content = <span>Condition B</span>;
  } else {
    content = <span>Neither</span>;
  }

  return <div>{content}</div>;
}

You have to do that whenever you need / want to use a statement.

Felix Kling
  • 705,106
  • 160
  • 1,004
  • 1,072
5

Calculating the value, binding to a variable, then outputting later is better. If you do want complex logic inline, you could use && and ||:

render() {
    return (<div>
        {
          this.props.conditionA && <span>Condition A</span>
          || this.props.conditionB && <span>Condition B</span>
          || <span>Neither</span>
        }
    </div>)
}

Edit:

As others pointed out, you can also remove that wrapping div and still use this approach:

render() {
  return (
    this.props.conditionA && <span>Condition A</span>
    || this.props.conditionB && <span>Condition B</span>
    || <span>Neither</span>
  );
}
Jacob
  • 72,750
  • 22
  • 137
  • 214
  • I like this - for some components, it's nice to have it all 'in front of you', as opposed to referring to other variables and/or components. I hear what you're saying though, be careful with the cognitive overhead. – Henry Aug 07 '16 at 04:28
1

If your condition is as simple as what you expressed, I think you can still use ternary as @SkinnyJ mentioned above. It's quite elegant, but I get your concern if there are lot of these conditions to check. There's one other way to solve this problem: using switch statement.

const props = {
  conditionA: "this is condition a"
};

let value;

switch (Object.keys(props)[0]) {
  case "conditionA":
    value = "Condition A";
    break;
  case "conditionB":
    value = "Condition B";
    break;
  default:
    value = "Neither";
}

console.log(value);

There are a couple of assumptions being made here. That the object is not null and that it has only one property.

But if those are true, for scenarios like this, switch might be more performant. This might be of interest for you:

Javascript switch vs if else

Community
  • 1
  • 1
KumarM
  • 1,631
  • 1
  • 18
  • 26
1

If any one still facing this issue, please paste below line in your eslintrc.js file.

"no-nested-ternary" : "off" 

This will allow you to start using nested ternary in your jsx code.

Meloman
  • 2,745
  • 3
  • 35
  • 39
0

Indeed, that is not the way.

var element;
if (this.props.conditionA) {
    element = (<span>Condition A</span>)
} else if (this.props.conditionB) {
    element = (<span>Condition B</span>)
} else {
    element = (<span>Neither</span>)
} 
...
    {element}
Hunter
  • 159
  • 1
  • 7