DEV Community

Discussion on: 4 Ways to Render JSX Conditionally in React

 
joelbonetr profile image
JoelBonetR 🥇 • Edited

You'll need to USE this custom hook anyway inside your component, isn't it?

Those are two different things, you can simplify as much as you can the functions, apply SOLID into them and extract functions from components, but a component itself will probably need any hook (being custom or not) and some presentation logic.

It's common to use this pattern in Next JS, specially when you use SSR to avoid client-server missalignments:

if( !someProp ) return null;
Enter fullscreen mode Exit fullscreen mode

While it's not so common in React, is also perfectly valid as defensive programming technique when a prop is required for a component to render properly.
It's placed at the beginning of the component, pretty understandable and suits any case in which a default prop value is not beneficial or, if you've preference for other patterns, we can say it's beneficial whenever a ternary would be worse.

Also consider that:

function Test({ userName }) {
  return userName && (<p>hi {userName}!</p>);
}
Enter fullscreen mode Exit fullscreen mode

Using this pattern (or similar ones) we receive undefined as return value whenever Test component either doesn't receive a prop or the prop evaluates to falsy.

So if you do something like:

/**
 * Returns a message depending on the quest result
 * @param {boolean} winner
 */
function QuestResult({ winner }) {
  return winner && (<p>You {winner ? 'WIN' : 'LOSE'}!</p>);
}
Enter fullscreen mode Exit fullscreen mode
export default function Whatever() {
  return (
    <div className="results">
      <h1>Quest Finished</h1>
      <h2>Result</h2>
      <QuestResult winner={false} />
    </div>
  );
}
Enter fullscreen mode Exit fullscreen mode

You'll get no message if you lose because winner is false, so it can cause non desired side effects.
So it's better to stablish that pattern as default one (from my experience):

/**
 * Returns a message depending on the quest result
 * @param {boolean} winner
 */
function QuestResult({ winner }) {
  if( typeof winner !== 'boolean' ) return null;
  return <p>You {winner ? 'WIN' : 'LOSE'}!</p>;
}
Enter fullscreen mode Exit fullscreen mode

Of course you can do the same condition with a ternary:

/**
 * Returns a message depending on the quest result
 * @param {boolean} winner
 */
function QuestResult({ winner }) {
    return typeof winner !== 'boolean' ? <p>You {winner ? 'WIN' : 'LOSE'}!</p> : null;
}
Enter fullscreen mode Exit fullscreen mode

but some components grow inevitably so they will become less readable plus this way you can control the condition easily and not having it coupled to the main return of the component. Easier to spot in PRs also!
Just look at this super simple example, we get a nested ternary here.
Is it worthy to decouple the message on a function getResultMessage(winner) or is better to use the other pattern?
And we even considered the hooks in the example above.

export default function MyComponent(props) {
  if( !props ) return null;
  // effects, states, whatever
  return <Whatever props={props} />
}
Enter fullscreen mode Exit fullscreen mode

In this case nothing will be executed if props is not set (or falsy)

export default function MyComponent(props) {
  // effects, states, whatever
  return  props ? <Whatever props={props} /> : null;
}
Enter fullscreen mode Exit fullscreen mode

In this one they will be (What a waste, huh?)