Conditional wrapping in React

This is something you do not always need, but I wrote this article for those looking for it.
Sometimes we might have a generic element, a specific component that renders inside a modal.
When a specific flag is set, the component should get a parent wrapper to display it in a different variant.
We could use an if…else statement, but it looks messy.
Conditional wrapping in React
Let’s say we got specific service cards to make it a bit easier to follow. In some cases, they explain a service, but in others, they need to link to a detail page.
The component might look like this.
1 2 3 4 5 6 7 |
<span class="kd">const</span> <span class="nx">ServiceCard</span> <span class="o">=</span> <span class="p">({</span> <span class="nx">title</span><span class="p">,</span> <span class="nx">description</span><span class="p">,</span> <span class="nx">image</span><span class="p">,</span> <span class="nx">url</span> <span class="p">})</span> <span class="o">=></span> <span class="p">{</span> <span class="k">return</span> <span class="p">(</span> <span class="o"><</span><span class="nx">section</span><span class="o">></span> <span class="o"><</span><span class="nx">h2</span><span class="o">></span><span class="p">{</span><span class="nx">title</span><span class="p">}</span><span class="o"><</span><span class="sr">/h2</span><span class="err">> </span> <span class="o"><</span><span class="nx">p</span><span class="o">></span><span class="p">{</span><span class="nx">description</span><span class="p">}</span><span class="o"><</span><span class="sr">/p</span><span class="err">> </span> <span class="o"><</span><span class="nx">img</span> <span class="nx">src</span><span class="o">=</span><span class="p">{</span><span class="nx">image</span><span class="p">}</span> <span class="nx">alt</span><span class="o">=</span><span class="p">{</span><span class="nx">title</span><span class="p">}</span> <span class="sr">/</span><span class="err">> </span> <span class="o"><</span><span class="sr">/section</span><span class="err">> </span> <span class="p">);</span> <span class="p">};</span> |
As mentioned, what happens if we need to wrap this whole thing in a link element when the URL exists?
We could use the if…else loop.
1 2 3 4 5 6 7 8 9 10 11 12 |
<span class="kd">const</span> <span class="nx">ServiceCard</span> <span class="o">=</span> <span class="p">({</span> <span class="nx">title</span><span class="p">,</span> <span class="nx">description</span><span class="p">,</span> <span class="nx">image</span><span class="p">,</span> <span class="nx">url</span> <span class="p">})</span> <span class="o">=></span> <span class="p">{</span> <span class="k">return</span> <span class="p">(</span> <span class="o"><</span><span class="nx">section</span><span class="o">></span> <span class="p">{</span><span class="nx">url</span> <span class="p">?</span> <span class="p">(</span> <span class="o"><</span><span class="nx">a</span> <span class="nx">href</span><span class="o">=</span><span class="p">{</span><span class="nx">url</span><span class="p">}</span><span class="o">></span> <span class="o"><</span><span class="nx">h2</span><span class="o">></span><span class="p">{</span><span class="nx">title</span><span class="p">}</span><span class="o"><</span><span class="sr">/h2</span><span class="err">> </span> <span class="o"><</span><span class="nx">p</span><span class="o">></span><span class="p">{</span><span class="nx">description</span><span class="p">}</span><span class="o"><</span><span class="sr">/p</span><span class="err">> </span> <span class="o"><</span><span class="nx">img</span> <span class="nx">src</span><span class="o">=</span><span class="p">{</span><span class="nx">image</span><span class="p">}</span> <span class="nx">alt</span><span class="o">=</span><span class="p">{</span><span class="nx">title</span><span class="p">}</span> <span class="sr">/</span><span class="err">> </span> <span class="o"><</span><span class="sr">/a</span><span class="err">> </span> <span class="p">)</span> <span class="p">:</span> <span class="p">(</span> <span class="o"><></span> <span class="o"><</span><span class="nx">h2</span><span class="o">></span><span class="p">{</span><span class="nx">title</span><span class="p">}</span><span class="o"><</span><span class="sr">/h2</span><span class="err">> </span> <span class="o"><</span><span class="nx">p</span><span class="o">></span><span class="p">{</span><span class="nx">description</span><span class="p">}</span><span class="o"><</span><span class="sr">/p</span><span class="err">> </span> <span class="o"><</span><span class="nx">img</span> <span class="nx">src</span><span class="o">=</span><span class="p">{</span><span class="nx">image</span><span class="p">}</span> <span class="nx">alt</span><span class="o">=</span><span class="p">{</span><span class="nx">title</span><span class="p">}</span> <span class="sr">/</span><span class="err">> </span> <span class="o"><</span><span class="sr">/</span><span class="err">> </span> <span class="p">)}</span> <span class="o"><</span><span class="sr">/section</span><span class="err">> </span> <span class="p">);</span> <span class="p">};</span> |
But this shows duplicate code, so it’s a bit silly. If we need to style each element, we must modify it in two places.
So how can we better wrap this conditionally?
We can create a generic component that handles this for us, the component will be named ConditionalWrapper
, and it will take a condition, the wrapper, and the children it should wrap.
1 2 |
<span class="kd">const</span> <span class="nx">ConditionalWrapper</span> <span class="o">=</span> <span class="p">({</span> <span class="nx">condition</span><span class="p">,</span> <span class="nx">wrapper</span><span class="p">,</span> <span class="nx">children</span> <span class="p">})</span> <span class="o">=></span> <span class="nx">condition</span> <span class="p">?</span> <span class="nx">wrapper</span><span class="p">(</span><span class="nx">children</span><span class="p">)</span> <span class="p">:</span> <span class="nx">children</span><span class="p">;</span> |
With that in place, we can use it on our existing component to clean it up.
1 2 3 4 5 6 7 8 9 10 |
<span class="kd">const</span> <span class="nx">ServiceCard</span> <span class="o">=</span> <span class="p">({</span><span class="nx">title</span><span class="p">,</span> <span class="nx">description</span><span class="p">,</span> <span class="nx">image</span><span class="p">,</span> <span class="nx">url</span><span class="p">})</span> <span class="o">=></span> <span class="p">{</span> <span class="k">return</span> <span class="p">(</span> <span class="o"><</span><span class="nx">section</span><span class="o">></span> <span class="o"><</span><span class="nx">ConditionalWrapper</span> <span class="nx">condition</span><span class="o">=</span><span class="p">{</span><span class="nx">url</span><span class="p">}</span> <span class="nx">wrapper</span><span class="o">=</span><span class="p">{</span><span class="nx">children</span> <span class="o">=></span> <span class="o"><</span><span class="nx">a</span> <span class="nx">href</span><span class="o">=</span><span class="p">{</span><span class="nx">url</span><span class="p">}</span><span class="o">></span><span class="p">{</span><span class="nx">children</span><span class="p">}</span><span class="o"><</span><span class="sr">/a></span><span class="err">} </span> <span class="o">></span> <span class="o"><></span> <span class="o"><</span><span class="nx">h2</span><span class="o">></span><span class="p">{</span><span class="nx">title</span><span class="p">}</span><span class="o"><</span><span class="sr">/h2</span><span class="err">> </span> <span class="o"><</span><span class="nx">p</span><span class="o">></span><span class="p">{</span><span class="nx">description</span><span class="p">}</span><span class="o"><</span><span class="sr">/p</span><span class="err">> </span> <span class="o"><</span><span class="nx">img</span> <span class="nx">src</span><span class="o">=</span><span class="p">{</span><span class="nx">image</span><span class="p">}</span> <span class="nx">alt</span><span class="o">=</span><span class="p">{</span><span class="nx">title</span><span class="p">}</span> <span class="sr">/</span><span class="err">> </span> <span class="o"><</span><span class="sr">/</span><span class="err">> </span> <span class="o"><</span><span class="sr">/ConditionalWrapper</span><span class="err">> </span> <span class="o"><</span><span class="sr">/section</span><span class="err">> </span> <span class="p">)</span> <span class="p">}</span> |
And now, if we use our component, depending on whether we pass the URL. It will render with or without the href. And the best part is that we have no duplication in our elements.
For example, the following use case:
1 2 |
<span class="o"><</span><span class="nx">ServiceCard</span> <span class="nx">title</span><span class="o">=</span><span class="dl">'</span><span class="s1">test</span><span class="dl">'</span> <span class="nx">description</span><span class="o">=</span><span class="dl">'</span><span class="s1">foo bar</span><span class="dl">'</span> <span class="nx">img</span><span class="o">=</span><span class="dl">'</span><span class="s1">img1.jpg</span><span class="dl">'</span> <span class="o">/></span> |
It would return the following HTML output:
1 2 3 |
<span class="nt"><section></span> <span class="nt"><h2></span>test<span class="nt"></h2></span> <span class="nt"><p></span>foo bar<span class="nt"></p></span> <span class="nt"><img</span> <span class="na">src=</span><span class="s">"img1.jpg"</span> <span class="na">alt=</span><span class="s">"test"</span> <span class="nt">/></span> <span class="nt"></section></span> |
We will get the following output if we put the URL in the element.
1 2 3 |
<span class="nt"><section></span> <span class="nt"><a</span> <span class="na">href=</span><span class="s">"url"</span><span class="nt">></span> <span class="nt"><h2></span>test<span class="nt"></h2></span> <span class="nt"><p></span>foo bar<span class="nt"></p></span> <span class="nt"><img</span> <span class="na">src=</span><span class="s">"img1.jpg"</span> <span class="na">alt=</span><span class="s">"test"</span> <span class="nt">/></span> <span class="nt"></a></span> <span class="nt"></section></span> |
Pretty cool, right?
The main magic, of course, happens in the ConditionalWrapper component and, to be precise, the wrapper argument.
Since we pass the children (which is a React default prop), we can see that the use case of our function as in wrapper={children => <a href={url}>{children}</a>}
states.
- If the condition is met
- Wrap the children in this specific element
There will only be a handful of times when you might need this function, but it can be a huge lifesaver.
Note: big thanks to Olivier for the original idea!
Thank you for reading, and let’s connect!
Thank you for reading my blog. Feel free to subscribe to my email newsletter and connect on Facebook or Twitter
Source: https://dev.to/dailydevtips1/conditional-wrapping-in-react-46o5