Using Immediately Invoked Function Expressions (IIFEs) in React for conditional rendering, especially with enums, and enhancing readability by using a helper function called renderInline
to clean up the syntax
One thing I like to do (which is controversial with a few of my colleagues) is to use an IIFE when rendering nested React components. In a way, this looks a lot like render props (especially using the children
prop as a render prop), which was definitely the craze before Hooks were the new (and much more ergonomic) way of composing behavior within React.
<div>
(() => {
return <p>This is rendered from an inline IIFE!</p>
})()
</div>
I like using this IIFE strategy when there’s just enough rendering logic to make a nested component complex to render, but not so much to make me feel like it’s worth the trouble to make a child component just for some rendering logic that’s used in one place.
The use case in which this shines is for switch statements. Suppose you have an enum in which you render a different thing depending on the enum value. By using an IIFE, you can easily convey that you are rendering different things that will be dependent on the enum value you are passing in.
function MyComponent(props: { check: MyEnum }) {
return (
<div>
{
(() => {
switch(check) {
case MyEnum.ValueA:
return <>...</>;
case MyEnum.ValueB:
return <>...</>;
default:
exhaustiveCheck(check);
}
})()
}
</div>
);
}
To make this look a little more ergonomic, I usually create some kind of helper that abstracts out the gross parentheses that make IIFEs hard to identify. I’ll usually make a helper called renderInline
:
export function renderInline(render: () => JSX.Element): JSX.Element {
return render();
}
While this helper seemingly does nothing, it can help clean up the above a little, at the very least adding a few points to readability and clarity to the original IIFE code.
function MyComponent(props: { check: MyEnum }) {
return (
<div>
{
renderInline(() => {
switch(check) {
case MyEnum.ValueA:
return <>...</>;
case MyEnum.ValueB:
return <>...</>;
default:
exhaustiveCheck(check);
}
})
}
</div>
);
}
And that’s it! Honestly, if it gets any more complex than a switch statement, I will usually then pivot to using a child component. But I’m surprised at how often I will reach for this technique, especially in a codebase where there’s a lot of “types” of things with conditional rendering for each of the types (like at Cocoon).