Optimizing Conditional Rendering in React

Cole Williams
Dec 20, 2016 · 5 min read

We know that React will crawl the Virtual DOM top to bottom looking for changes in the component tree, and updating the corresponding part of the DOM. But we can help React do this even better by writing proper conditional statements.

Conditional rendering in React has been a long, and exhausting discussion. There are dozens of ways to tell React to render or not render a component given a certain condition or state/prop change. You may not know that your current React code is actually creating costly unmounting and re-mounting of components. I’m hoping to shed some light on optimizing your conditional rendering with React

One of the most common mistakes people new to React make, is having multiple if/else statements, and various return statements in their component. For example :

— Anti-pattern for conditionally rendering React components

Or even worse……

— *Run and Hide — Horrible mega anti pattern ! ! !

For now, lets take a look at the first code snippet and the call to renderPoorly…

Here, on each call to render(or in this case, renderPoorly), React will first check if this.state.showHeader is truthy. Then, it will run its diffing algorithm to determine which DOM nodes have changed. And in this case, its all of them.

But we don’t want to unmount and then mount the Photo and Comments components?! Indeed. We only want to add the Header component to the existing sub tree, and leave Photo and Comment components alone, so as to not cause reflow.

Lets say to start on the first render, this.state.showHeader is true. This is a very simplified depiction of the component tree React will create in the Virtual DOM :

React renders the Header, Photo and Comments components and their children without any problems or performance bugs.

Now, lets say theres some user interaction, and we no longer want to show the header. On our render call, showHeader is set to false, our conditional check fails. We only want to display the Photo and Comments components, but no Header component. Heres the example code again:

Condition did not pass if statement, default return

Here, React is forced to unmount Photo and Comments components, and remount them. This is a partial reflow, which is expensive and defeats the very reason of using React. The diffing algorithm will run a check comparing the element types at each position(Made-up naming convention im using for example purposes)

If this.state.showHeader is true, the Header component will be rendered in position 1. If its falsey, the Photo component will take position one, and following components will move up one position, to a different position.

React will see that the components at position 1 AND position 2 are of different types, so it will unmount the Header component, and mount the Photo component in its place. It will do the same for the Photo and comments components. This unmounting and re-mounting is a partial reflow goes directly against what React tries to optimize. And costs you more $$$.

You can imagine how costly this may be if you are unmounting and mountain data-heavy elements, like an animation or video.

Lets add some changes to our original code…

Optimized conditional rendering

Here we are using an embedded JSX expression. The React docs explain that:

It works because in JavaScript, true && expression always evaluates to expression, and false && expression always evaluates to false.

Therefore, if the condition is true, the element right after && will appear in the output. If it is false, React will ignore and skip it.

Lets say this.state.showHeader is falsey, our component tree will now look like this…

Sub-tree with this.state.showHeader = false

Our Header component is replaced with a null component. If the inline condition isn’t met ({this.state.showHeader && <Header />}), React will render null in place of the component, at the same position.

Now, some event triggered a state change and we want to display the Header component. On the next render call (aka any update) React will run its diffing check(overly simplified for our purposes) like this:

When this.state.showHeader becomes truthy, React will start crawling from top to bottom checking for diffs. It will first compare Null to the Header component — see they are different types and mount a Header component in place of null. It will then run a check on the Photo and Comments components — see that they are both of the same type and same position, and NOT unmount and remount them — but leave them be. Aaaahhhhhh, the beauty of React. It does so much heavy lifting for us :)

A similar approach to our previous, renderBetter example — is declaring a variable in the render method and setting the value of that variable to either null, or the desired component. This will have the same desired, optimized outcome. Our code would look something like this:

Another good example of conditional rendering

If this.state.showHeader is falsey, just like earlier, it will render null for the {util} element(because its JSX it must be wrapped in curly brackets). When it becomes truthy, it will diff — see they <Header /> should go in place of null — and both Photo and Comments components do not need to change or unmount.

Moral of the story: never have multiple return statements in your render method. Either use embedded JSX expressions or a variable assignment and you’ll gain substantial optimizations

React is lightning fast and maintaining UI or application state. But we can help it become even more efficient and cost effective if we write our code in such a way.

We know that React will crawl the Virtual DOM top to bottom looking for changes in the component tree, and updating the corresponding part of the DOM. But we can help React do this even better by writing proper conditional statements

Cole Williams

Written by

JavaScript Engineer. Brain, Earth, and React.js Lover.

Welcome to a place where words matter. On Medium, smart voices and original ideas take center stage - with no ads in sight. Watch
Follow all the topics you care about, and we’ll deliver the best stories for you to your homepage and inbox. Explore
Get unlimited access to the best stories on Medium — and support writers while you’re at it. Just $5/month. Upgrade