One of my clients is using an odd React pattern: They put only JSX in components


One of my clients is using an odd React pattern: They put only JSX in components. All logic is placed in a custom hook with matching name.

Example:
Product.tsx // Just JSX
useProduct.tsx // Product logic

I talked them out of this pattern using the justifications below.

Benefit:
The component file is simple. It’s just JSX.

Downsides:
1. Reduces locality of behavior. Code with high locality of behavior is generally easier to read.

2. Have to frequently jump between at least two files to work with the component and fully understand it.

3. More code. Must export all state and functions from the hook, then reimport and destructure the properties returned from the hook in the component.

4. In many cases, the hook contains code it doesn’t use. It merely exports code so the component can import it.

5. Have to repeat many component props in custom hook since most component props are read in the custom hook.

6. Unused code can’t be detected via Knip, since the component consumes all the hook’s props.

7. Encourages creating a monolithic custom hook instead of abstracting small, focused, well-named custom as when needed. A monolithic hook doesn’t help break down complexity. It’s like a function named “function”.

8. React encourages grouping related JS, and JSX in the same file, since they’re fundamentally intertwined. The component is the concern. When the component gets too big, we can extract *components*. When logic gets complex, we can extract hooks.

What I suggest instead:
1. Put logic in the component by default.
2. JSX too long or needs to be reused? Extract a component.
3. Logic too intimidating or needs to be reused? Extract well-named, focused custom hooks.

To be clear: Extracting focused logic into well-named hooks is useful.

I'm critiquing the pattern of having only JSX in the component with a single custom hook for everything else.

So, yes, extract hooks as needed. But avoid creating a single monolithic hook per component.

View original on X