Back to Article index

Start with Bad Code

Why starting with a large React component can be safer than splitting too early, and how to decide when an abstraction has earned its place.

Published
June 11, 2024
Read in Japanese

Avoid repetition. Separate concerns. Both principles help us write readable React. Neither means that smaller, more fragmented code is always better. A component combines UI, behavior, and state. Two components can look alike and still behave very differently.

For example, one control may be a <button>, while another uses the same styling but must be an <a> because it navigates somewhere. In other cases, complex logic belongs in a Custom Hook, or a small component has a real opportunity for reuse.

This article describes how I decide when to split a React component. These are heuristics, not universal rules, but they provide a practical place to start.

Start with a large component

I usually begin with one large component containing both its logic and JSX. I still follow established team rules—such as putting API calls in Custom Hooks—but I avoid creating more boundaries before I understand the feature.

Writing a PoC that satisfies the requirements is easier than guessing every future abstraction in advance. Once the code works, its responsibilities become visible. Splitting a large component later is usually easier than reassembling a collection of components that were separated too early.

A perfect design cannot be known at the start. If there is not yet a concrete reason to split the code, keeping it together can be the more maintainable choice.

Split when the component creates a problem

When the decision is unclear, look for a real problem. Consider splitting when the component has become difficult to understand, change, test, or reuse. Premature boundaries add indirection and can turn an uncertain design into the wrong abstraction.

Make sure appearance and behavior align

Imagine several components that look similar in Figma but behave differently in the product. Before combining them, ask whether one props type can represent every case without awkward exceptions.

If each component contains one button and can accept the same VoidFunction click handler, a shared visual component may be straightforward. If unifying the types requires many conditions or escape hatches, separate components are often clearer—even when they look alike.

Split along testing boundaries

UI, behavior, and state can require different kinds of verification. Visual details may be covered by review, visual regression testing, and accessibility tests, while behavior may be tested independently. A logic test often does not care how the React component renders.

When behavior becomes complex, extracting a Custom Hook can make that boundary explicit. The logic can be tested without rendering the full UI, which may also make the test easier to maintain.

I do not extract every API call or simple state update. For small amounts of logic, I prefer to mock HTTP requests with MSW (Mock Service Worker) and test the component as a whole. Splitting tiny pieces creates more implementation and test files to manage. If the large component is not causing a problem, leaving it intact is often simpler.

Keep private files nearby

Place a Custom Hook or internal component used by only one component in the same directory as its consumer. If the main component is population/index.tsx, for example, its private Hook might be population/useX.ts.

This makes the scope visible: the file is an implementation detail, not a shared utility. It also keeps related files together when the component is refactored or removed.

Summary

Perfect code cannot be written in advance. As development continues, new requirements reveal better boundaries. Write code that is honest about what you know today, then reshape it when a real problem appears.

Start with the large component and extract or share code only after the need becomes clear. Postponing a split is a valid design decision. Sometimes leaving code that looks “bad” today is what preserves the freedom to create a better design tomorrow.