Inline conditional rendering
Proposed change
Write conditional rendering in JSX inline instead of moving it out into separate functions. (1)
If the component(s) rendered based on the condition is too complex, or has a natural connection through their role or common feature, possibly for reusability, the components could instead be moved into a separate component. (2)
A separate component should also be used instead of messy ternary operators, even if it is not a candidate for reusability outside the module. (3)
Consider what conditions belongs naturally in the surrounding logic, and what belongs inside the rendering logic. For instance, a toggle state specific too the UI that renders a reusable component, belongs outside the component. However, if the component renders a specific entity, and one of the known properties of that entity is a value that can be controlled through a CMS for hiding that specific entity, it could make more sense to have that condition inside the component instead of in the parent that renders it.
If the conditions is complex, they should be assigned to a variable with a name that makes the complexity easier to understand. (4)
How it looks now
function MyComponent({ type, title, message }: Props) {
return (
<>
<ComponentWithoutConditions />
{type === 'Error' ? (
<Icon type="error-message" />
) : type === 'Warning' ? (
<Icon type="warning-message" />
) : (
<Icon type="info-message" />
)}
{getFoo()}
{getBar()}
</>
);
function getFoo() {
if (!foo) return null;
return <Foo />;
} // (1)
function getBar() {
if (!time > openingHours && time < closingHours) return null;
return <BarComponent>{/* 25 lines of JSX */}</BarComponent>;
} // (2)
}
Solution
function Bar() { // (2)
return (
return <BarComponent>{/* 25 lines of JSX */}</BarComponent>;
)
}
function MyIcon({ type: string }): JSX.Element { // (3)
switch(type){
case 'Error':
return <Icon type="error-message" />;
case 'Warning':
return <Icon type="warning-message" />;
default:
return <Icon type="info-message" />;
}
}
function MyComponent({ type, title, message }: Props) {
const barIsOpen = (time > openingHours && time < closingHours); // (4)
return (
<>
<ComponentWithoutConditions />
<MyIcon type={type} />
{foo && <Foo />}
{barIsOpen && <Bar />}
</>
);
}
Motivation
Inline conditions and rendering makes the code simpler and more linear to read. You see what is rendered while reading the rest of the tags/components the component returns, without having to jump up and down between the conditional functions and the return statement.
Proposed transition strategy
This syntax is tightly connected to how the logic of the UI features work, so I suggest using it gradually as a new pattern of new/rewritten code to avoid too much work rewriting all existing code with the existing pattern.