Skip to content
Bernardo Fernandez

Engineering · August 20, 2026 · 5 min read

Why I stopped putting business logic inside React components

Components are where bugs get discovered, not where rules should live. What changed when I moved decisions out of the view layer — and where I draw the line now.

The first version of any feature puts the logic right there in the component. It's fast, it's obvious, and it works — until the second screen needs the same rule and copies it, or the rule changes and someone finds the third copy two months later.

That was me for a while: a date comparison here, a currency format there, a status check embedded in JSX. Each one harmless. Together, they made every screen slightly different from every other one, and none of them wrong in a way a test could catch.

Where I draw the line now

My rule is blunt: components render and capture intent; they don't decide. If a piece of code answers 'what is this UI state?', it can live in the component or a hook. If it answers 'what does the business allow?', it belongs in typed functions with no knowledge of React at all.

The type system does more work than any architecture diagram here. A status that is a string with six valid values is a bug waiting for a typo; the same status as a union type makes half the invalid states impossible to write. The component then becomes a rendering of a decision that was already made.

What actually changed

Domain rules became testable without rendering anything. Refactors stopped being archaeology. And the components got boring — which is the goal. A boring component is one whose bugs are about rendering, not about rules nobody remembers writing.

The framework didn't matter as much as I expected: the discipline is the same whether the view is React or something else. The view layer is for translation, not for policy.

Thinking about something like this?

Let's talk about your project