React Anti Patterns Part 2
Tags: react, todayilearned
Published: 2020-02-14 20:42:31

The original post lives <a href="https://www.grantwatson.app/posts/react-anti-patterns-part-2" target="_blank">here</a>

<p>     Conditional rendering with React is just a matter of deciding which element      object to return. You can use if and switch statements, the conditional      operator, and even the && operator!      This gives you a lot of power — I’ll go into the details next week. The      problem is that all of this power makes it easy to shoot yourself in the      foot. Lucky for you, getting familiar with these 3 anti-patterns will help      help you avoid most of the pain. I’ll start with the issue I run into most… </p>  <p>     <h3><code>         someNumber && ...     </code></h3>      Let’s do a little quiz on the && operator: what is the value of x?      <code> let x = 0 && \"1\" </code>      You can check your answer below:     <code> The value of x is 0 </code>      There’s something special about 0: it’s the only falsy value that JSX renders as text.      This makes it generally a bad thing to guard on it.      For example, say you’re printing verses of “bottles of beer”, but you don’t want to print      the last verse with “0” bottles of beer. You might attempt to handle this by prefixing      the verse with bottlesOfBeer &&:          <pre><code>         import React from 'react'         import ReactDOM from 'react-dom'          let bottlesOfBeer = 0          ReactDOM.render(         bottlesOfBeer &&         <h1>             Take one down and pass it around,&nbsp;             {bottlesOfBeer} bottles of beer on the wall.         </h1>,         document.getElementById('root')         )     </code></pre>      Oops! A random 0 appeared in your app. </p> <p>     One trick to avoid this is to coerce the left-hand side of your && operator into      a boolean by using the !! operator. To see this in action, try removing the !! operator from the below example.      <pre><code>         import React from 'react'         import ReactDOM from 'react-dom'          let bottlesOfBeer = 0          ReactDOM.render(         <div>             {              !!bottlesOfBeer &&             <h1>{bottlesOfBeer} bottles of beer on the wall.</h1>             }         </div>,         document.getElementById('root')         )     </code></pre>     I run into this issue even after years of working with React. It’s easy mistake to make.      But knowing why a random 0 has appeared in your app can turn minutes of debugging into seconds.  </p> <p>     <h3>I heard you like Conditional operators so I put a Conditional operator in your Conditional operator</h3>     One of the things about conditional operators, is that you can put them in other conditional operators. This is a little hard to explain,      so the best way to see why this is a bad idea is to look at this example.      <pre><code>         const Button = props =>         props.status === 'busy' ?             <InnerButton {...props} icon={<Icon spin name=\"spiral\" />} /> :         props.status === 'error' ?             <InnerButton {...props} icon={<Icon name=\"error\" />} /> :         props.status === 'disabled ?             <InnerButton {...props} disabled /> :         <InnerButton {...props} />     </code></pre>      This hypothetical component will render a Button element, and will pass in different props depending on the value of props.status.      The component will work; it’ll do exactly what it’s supposed to. But imagine that you don’t already know what it’s supposed to do,      and you’re trying to figure it out… yuck.      Conditional operators are a great tool when used in moderation. Some people will tell you that you should never use a      conditional operator inside another one. I’m a little more moderate, I think it depends on the situation.      But try not to go overboard, or you might end up with a bit of a hangover. </p> <p>     <h3>If, Only, Else, etc…</h3>     You might wonder why nobody has created an Only component that can be used to simplify conditional rendering.      <pre><code>         <Only when={user}>             <h1>Hi, {user.name}!</h1>         </Only>     </code></pre>      But actually… many people have.      The reason that conditional components don’t catch on is that they have some downsides that aren’t immediately obvious. In particular,      unlike JavaScript’s if statement, their children will be evaluated regardless of whether the condition is met.      At first glance, this Only component seems to work great. So what’s the problem?      Let me start by asking you a question: what do you think will happen if you set user to null? Have a think about it, then try it out in the above editor to see for yourself.      Did you give it a shot? Then let’s continue!      The reason that setting user to null results in an error is that accessing user.name will throw an error if user is null. Remember, the children of Only are just      arguments to a call to <code>React.createElement();</code> they’ll be evaluated regardless of the value of the when prop! If you’re not convinced, click “compiled” and take a look.      In contrast, if you were to implement the same component using an && guard, then the h1 tag will not be evaluated unless user has a value.      Try confirming this for yourself by changing user to null in the example below:      <pre><code>         import React from 'react'         import ReactDOM from 'react-dom'          function WhatAHangover(props) {         let user = props.user         return user && <h1>Good morning, {user.name}.</h1>         }          ReactDOM.render(         <div>             <WhatAHangover user={{ name: 'Dave' }} />             <p>After sleeping on it I feel like maybe I can do that.</p>         </div>,         document.getElementById('root')         )     </code></pre> </p>