Ryo Tanaka
Writing
ReactArchitectureTypeScript

The Component Boundary Is a Design Decision

·Ryo Tanaka

Every time you extract a piece of JSX into its own component, you're making a bet.

You're betting that this chunk of UI will be reused elsewhere, or that isolating it will make testing easier, or that the file was getting too long. Sometimes the bet is right. Often it's premature.

The cost of over-componentization

React components carry overhead that's easy to underestimate:

  • Each component is a closure over its props and context
  • Overly granular trees make co-locating data with render logic harder
  • React.memo and useCallback become necessary — then confusing — when you've split too eagerly

I've seen codebases where a simple <UserAvatar /> component has been broken into <AvatarContainer>, <AvatarImage>, <AvatarInitials>, and <AvatarStatusDot> — each in its own file, each with its own prop type, none reused anywhere outside. This is componentization for its own sake.

My heuristics

Split when there's a render budget reason: If a subtree renders on every keystroke but doesn't need to, wrapping it in a memoized component saves real work.

Split when the code becomes hard to hold in your head: A component file over ~250 lines is hard to navigate. But split it at logical seams — not arbitrary line counts.

Split when you need a different error boundary or suspense boundary: These structural React features require component boundaries to work.

Don't split for reuse that hasn't happened yet: Wait for the second use case. You'll know more about the right abstraction when you have two concrete examples.

Co-location as the default

The default should be: keep things together until there's a reason to pull them apart.

Data fetching, event handlers, and the JSX that uses them should live in the same file until the cost of proximity outweighs the benefit. This is the principle behind React Server Components too — the data and the render are co-located at the server, minimizing the surface area for bugs.

Component boundaries are architectural lines. Draw them with intention.