Let's first look at how to conditionally render in React and then dive into several experiments that might present more readable ways to conditionally render in React.
Scenario: Show a login component vs a register component given the property "isLoggedIn"
Used quite often the "&&" is easy to throw in for some quick conditional logic.
Given this simple scenario, a guard clause works here and is a bit more readable than the "&&".
This also is easier to understand; being able to one line this is pretty nice.
Scenario: Show a login component vs a register component given the property "isLoggedIn", in addition show the "UnicornLogin" component if the "isUnicorn" flag is true.
This is awful. It is clear that the "&&" is only good to use sparingly and only when there is one condition.
Less awful, but this is going to make things tricky if you ever wanted to wrap each of the components being returned with another component.
Also, less awful, yet prone to the same struggles as using if/else statements when more changes inevitably occur.
Now that we've seen how to use conditional rendering in React, let's take a look at some specific examples where conditional rendering may not do what you expect.
When using "&&" to check the length of a data set and then mapping over it will render "0" when that list is empty.
This was recently highlighted by Kent C. Dodds in his article.
The code below will render "0" when data is empty.
This can be resolved by either using a ternary operator instead of "&&".
This can also be resolved by either using an if/else statement.
This React Native specific, but when conditionally rendering a
This will crash your app if "message" is ever 0:
Ternaries are nice if you have one condition. However, it is too easy to not refactor and quickly add another check and then another.
This is a simple example, you can imagine what this would look like if each component we rendered were 5-10 or more lines long.
We've taken a look at how to write basic conditional statements in React, along with some pitfalls to avoid. Let's consider how we can write better conditional code in React.
I think it is easier to read JSX if your brain only has to parse
Let's consider creating a component called "RenderIf" and takes a boolean property of "isTrue" and renders its children.
Re-writing our example with the "RenderIf" component, I'm mostly looking at XML. However, there is still some boolean logic that could be cleaned up.
We can clean up the boolean logic by wrapping our "RenderIf" component.
I personally like reading more declarative React, however one of the pitfalls that I had not mentioned is that the children for the RenderIf component will still go through a render cycle even if our condition is false. This is because RenderIf is still JSX vs being straight javascript.
So, how do we get around this?
I happen to write a RenderIf Babel plugin that does just this! You can find the code out on my GitHub here.
Essentially, this plugin will take code that looks like this:
and turn it into this:
So, we are getting our declarative syntax and when it is transpiled, we get the more performant version. Also, if you use this plugin you won't have to write your own RenderIf component! 🎉
Often times if there is an accumulation of complexity in a component it is a sign that there are components that should be refactored out. Although knowing exactly when and how to refactor is hard to know, here are some general rules of thumb that you might consider.
Keep components to less than 100 lines. As you start to get into the 100-250 line territory you should really start thinking about refactoring. If you are at 500+ lines of code, that should be refactored as soon as possible.
Cyclomatic complexity is the number of paths through your code. So, if you have a simple if/else block, then it has a cyclomatic complexity of 2, where as if you had a block of if/else if/else if/else if/else, the cyclomatic complexity would be 5.
You can enforce this by using the ESLint complexity rule
It is up to you what level of complexity is appropriate, but somewhere around 4-5 is usually a good place to start.
We can write cleaner React by extracting out distracting syntax and knowing when to refactor.
Creating a helper component like "RenderIf" is an example in how you could extract out conditional logic into a declarative syntax. This makes it a little bit easier for your brain since it is mostly taking in XML. Building on that idea, we can wrap our helper component to create a richer set of conditional components that add even more context.
At the end of the day, a component that is large and complex, no matter how clean the React is, will be prone to bugs and simply not fun to work on. It is a good practice to know when to refactor, and to be disciplined to do that refactor when you know it needs to happen.
Happy coding and keep your React clean!
Often times React components become hard to understand due to conditional rendering. At first a simple if/else or ternary operator appears benign to your overall readability, but over time as changes occur another if/else or ternary may be added. Compounding this issue is when conditional operators are nested many times, which unfortunately is too easy to do.
Are you ready to build something brilliant? We're ready to help.