Conditionally Rendering React Components with an HOC

Conditional rendering in React is pretty straightforward and we do it everywhere. In some cases, though, a tiny abstraction can clean up our code and keep us from repeating ourselves. Here’s a simple Higher Order Component (HOC) for conditionally rendering a component or fragment if-and-only-if it has children.

Why bother?

I often find myself building components with a number of slots, some of which may be optional. If there’s any container styling around these optional slots, its naturally desirable that we’d only render the containing bits when slot content is actually provided.

As an example, imagine a composite heading component consisting of a main heading slot and optional slots for subheading and kicker. It may look something like this:

const Heading = ({ text, sub, kicker }) => (
	<>
		{_.isNil(text) && <h3 className="kicker">{kicker}</h3>}
		<h1 className="heading">{text}</h1>
		{_.isNil(sub) && <h3 className="sub-heading">{sub}</h3>}
	</>
);

This is fine, but its not the most readable code, especially when using something like Lodash’s isNil() function to avoid tripping over falsey values.

Clean it up

Using an HOC, we can both clean up the code a bit and abstract the logic used to check the condition (Lodash in our case):

const ifChildren = Component => props => 
	_.isNil(props.children) ? React.Fragment : <Component {...props} />;

Now our Heading component can be written like this:

const Heading = ({ text, sub, kicker }) => (
	<>
		{ifChildren(<h3 className="kicker">{kicker}</h3>)}
		<h1 className="heading">{text}</h1>
		{ifChildren(<h3 className="sub-heading">{sub}</h3>)}
	</>
);

or better yet:

const Fragment = ({ children, ...props}) => ifChildren(<h3 {...props}>{children}</h3>);

const Heading = ({ text, sub, kicker }) => (
	<>
		<Fragment className="kicker">{kicker}</Fragment>
		<h1 className="heading">{text}</h1>
		<Fragment className="sub-heading">{sub}</Fragment>
	</>
);