If I had to choose just one principle to help frontend developers write better React code, it would be this: use dumb components.
This approach is often underestimated or used only for shared UI libraries. But in my experience, applying it regularly — even in app-specific parts — always makes the code cleaner and easier to manage.
Let’s dive into what this means in practice.
✅ What Are Dumb Components?
Dumb components — also called presentational components — focus only on how things look. They are:
- Not responsible for business logic or application-level state.
- Driven entirely by props — they receive all data and event handlers from the outside.
- Allowed to use local state, but only for things related to presentation (e.g. toggling a tooltip).
- Allowed to use context (like theming or localization), as long as it's not about application logic (like auth or cart data).
type UserCardProps = {
name: string;
avatarUrl: string;
};
export const UserCard = ({ name, avatarUrl }: UserCardProps) => (
<div className="user-card">
<img src={avatarUrl} alt={`${name}'s avatar`} />
<h2>{name}</h2>
</div>
);
Because they don’t handle logic, dumb components are easy to reuse, test, and understand.
🤔 What’s a Smart Component Then?
Smart components (also known as container components) are in charge of everything else:
- Fetching and preparing data
- Managing state with hooks like
useState
oruseReducer
- Handling business logic and user actions
- Connecting to app-level context or external stores
export const UserCardContainer = () => {
const user = useUser(); // gets user data from context or API
return <UserCard name={user.name} avatarUrl={user.avatarUrl} />;
};
Smart components do the heavy lifting, while dumb components focus only on rendering the UI.
👍 Why Dumb Components Are Great
Here’s why using dumb components makes a big difference:
- 🧩 Modular – each one has a clear and simple job
- 🔄 Reusable – works with different data without changes
- 🧪 Testable – no side effects, easy to write unit tests
- 🧠 Predictable – just look at the props to know how it works
- 👩💻 Maintainable – logic and UI are cleanly separated
When your codebase grows, this structure helps keep things organized and easier to change.
🛠️ When to Extract Dumb Components
There are two common cases where you should create dumb components:
1. Move logic up from a visual component
Sometimes you’ll notice multiple components each handling their own piece of state — but those pieces are connected. Instead of spreading logic around, move it up into one place, and pass the needed data and callbacks down as props.
🔍 Tip: This is especially useful when working in legacy codebases where logic and UI are mixed together.
2. Move visual parts out of a large smart component
It’s common to build everything in one big component at first. But when you notice that part of the JSX is just layout or display, it’s time to extract it.
This makes the smart component easier to understand, and the new dumb component easier to reuse elsewhere.
⚠️ Common Misconceptions
❌ “Dumb components can’t use
useState
”
✅ They can, as long as the state is only used for UI, not for app logic.❌ “Using context makes a component smart”
✅ Not always. If you use context just for themes or translations, it’s still presentational.
🧠 Bonus: Why This Matters Long-Term
In larger apps or teams, this pattern brings big advantages:
- Scalable structure – clear separation between logic and UI
- Better collaboration – easier to split work between devs and designers
- Smaller Git diffs – changing logic doesn’t touch UI and vice versa
- Easier testing – presentational components don’t need complex setup
- Safer refactoring – you can change one side (logic or UI) without breaking the other
This all leads to faster development and fewer bugs in the long run.
📚 Further Reading
✅ Final Thoughts
Dumb components are a simple idea, but they can seriously improve the way you build React apps.
They help you separate responsibilities, make your code easier to test and reuse, and keep things clean even as your app grows.
Start small — look for parts of your code that only handle display, and move them into their own components. You’ll quickly see the benefits.
Top comments (0)