DEV Community

Cover image for Cleaner React: Conditional Rendering

Cleaner React: Conditional Rendering

Matti Salokangas on September 25, 2020

Often times React components become hard to understand due to conditional rendering. Β At first a simple if/else or ternary operator appears benign ...
Collapse
 
rtivital profile image
Vitaly Rtishchev
const IfSingleItem = ({ children, data }) => <RenderIf isTrue={data.length === 1}>{children}</RenderIf>  
const IfDoubleItem = ({ children, data }) => <RenderIf isTrue={data.length === 2}>{children}</RenderIf>  
const IfMultiItem = ({ children, data }) => <RenderIf isTrue={data.length > 3}>{children}</RenderIf>

const RenderData = ({ data }) => {  
 return (  
   <>  
     <IfSingleItem data={data}>  
       <SingleItem data={data} />  
     </IfSingleItem>  
     <IfDoubleItem data={data}>  
       <DoubleItem data={data} />  
     </IfDoubleItem>  
     <IfMultiItem data={data}>  
       <MultiItem data={data} />  
     </IfMultiItem>  
   </>  
 );  
}  
Enter fullscreen mode Exit fullscreen mode

This looks really nasty. It's always better to such keep logic out of jsx. We have a switch operator for that.

Collapse
 
sturdynut profile image
Matti Salokangas

I see what you are saying; you could very well use a switch operator as well. The concept here was to demonstrate how you can wrap RenderIf to create a richer API for your JSX.

Collapse
 
rtivital profile image
Vitaly Rtishchev

What I'm saying is that RenderIf is a huge mess and should not be used

Thread Thread
 
sturdynut profile image
Matti Salokangas • Edited

I've used it on several projects where teams were really happy with it. I'm curious why you think it is a "huge" mess considering the alternatives and potential pitfalls?

Collapse
 
hoverbaum profile image
Hendrik

Cool idea. I think components like your RenderIf can help convey what you are doing. At least in complex scenarios, they can be easier to reason about than complex statements. Thus, gathering experience as to when to do this kind of refactoring is important, but a nice inspiration.

Collapse
 
alexkhismatulin profile image
Alex Khismatulin

There are also babel JSX extensions that allow conditional rendering like the following ones
npmjs.com/package/babel-plugin-jsx...
npmjs.com/package/babel-plugin-jsx...

Collapse
 
sturdynut profile image
Matti Salokangas

That is really nice! I think the one caveat here is that it is harder to discern the code paths in your components since the condition is nested in your component vs physically part of your component tree. I find it easier to see using RenderIf or something similar which also makes it easier for me to see the various conditions I need to test.

Collapse
 
alexkhismatulin profile image
Alex Khismatulin

100% agreed, but that’s still an option

Collapse
 
ramblingenzyme profile image
Satvik Sharma

I like the idea of pushing your conditions down your React tree wherever possible, so like passing isUnicorndown into the Login component and handling that condition internally.

Collapse
 
sturdynut profile image
Matti Salokangas

That works too. But then you are mixing presentation logic in with your component code vs having only what you need in your component. I think having your presentation logic outside of the component makes things easier to reason about and make sure that components aren't doing more than they should.

Collapse
 
ramblingenzyme profile image
Satvik Sharma • Edited

Not sure I agree, the whole point of props is to change what's rendered, from the user's perspective the difference is probably "the login is themed differently when I'm a unicorn", so what's the meaningful difference between, swapping a whole component in this level, doing the swap inside or changing styles internally, so why does it matter that it's handled outside the component or in it? It sounds to me like exactly part of the component's responsibility.

Also, turning JSX into a logic heavy DSL is not my jam at all.

Thread Thread
 
sturdynut profile image
Matti Salokangas

That is true. But, something still needs to conditionally render based on those prop changes. I've outlined many ways to do that in this post and suggested a way that I prefer using RenderIf. If it is not your thang, that's cool. Readability is subjective to some degree. I personally find it easier to take in JSX that looks more like HTML than a mix of HTML and JS if/else/switch statements.

Thread Thread
 
ramblingenzyme profile image
Satvik Sharma

For sure, which is why most of the time I prefer calculating as much as possible in plain JS so the JSX is mostly just JSX, even if it's just putting the ternaries into constants

Thread Thread
 
sturdynut profile image
Matti Salokangas

Totally. You can clean up a ton of JSX by extracting variables and doing calculations prior to rendering. That is a great point and I find myself doing those refactors when I'm trying to make components more readable.

Collapse
 
jacobmgevans profile image
Jacob Evans

XState and React Query I think helps a lot with this overhead. I loved the explanations super detailed and learned a lot about cyclomatic complexity.

Collapse
 
xavierbrinonecs profile image
Xavier Brinon

Amen

Collapse
 
johnsoncherian profile image
Johnson • Edited

The code below will render "0" when data is empty.
const RenderData = ({ data }) => data.length && data.map(...);

What about this.?
const RenderData = ({ data }) => (!!data.length) && data.map(...);

Collapse
 
sturdynut profile image
Matti Salokangas

That would return false. I think the trap here is that it is easy to forget to cast the data.length to a boolean type.