React Component Architecture: Clean & Mean

Hey! I'm Faiaz — a frontend developer who loves writing clean, efficient, and readable code (and sometimes slightly chaotic code, but only when debugging). This blog is my little corner of the internet where I share what I learn about React, JavaScript, modern web tools, and building better user experiences. When I'm not coding, I'm probably refactoring my to-do list or explaining closures to my cat. Thanks for stopping by — hope you find something useful or mildly entertaining here.
Designing React Components You Won’t Regret Later
Some components are smart.
Some are dumb.
Some do both and break up with you mid-render.
This post is about writing React components that make sense — to both the browser and your future self at 2AM.
Here’s what we’re covering in this fun ride:
📦 Atomic Design - Organize UI like Lego
🧩 Presentational vs Container — Divide and don’t conquer
🗂️ Folder Structures — End chaos before it starts
♻️ Controlled vs Uncontrolled — From inputs that behave
💡 Smart vs Dumb — Keep logic where it belongs
🔁 Render Props HOCs — Advanced reuse (that doesn’t fry your brain)
📦 Atomic Design — Lego Your UI
The Problem:
You dump all UI into one component file and scroll for years. Suddenly you're in a war flashback with div > div > span > flex > 😩.
The Solution:
Break UI into levels:
Atoms → buttons, inputs
Molecules → input with label
Organisms → login form
Templates → page layout
Pages → entire screens
Common Mistakes:
Making atoms that are basically molecules with drama
Naming things like
Button1,ButtonBig,ButtonFinalForReal
Fix Tips:
Name components by function, not feelings
Don’t over-modularize —
<Button>is fine,<ClickySquareThing>is not
🧩 Presentational vs Container Components — UI vs Logic
The Problem:
You’ve got one component trying to fetch data, loop it, render it, and apply inline styles like it’s getting paid per side-effect.
The Solution:
Split components:
Presentational: Pure UI, no logic
Container: Handles fetching, state, passing props
Example:
const UserList = ({ users }) => (
<ul>{users.map((u) => <li key={u.id}>{u.name}</li>)}</ul>
);
const UserListContainer = () => {
const [users, setUsers] = useState([]);
useEffect(() => { fetchUsers().then(setUsers); }, []);
return <UserList users={users} />;
};
Common Mistakes:
Presentational components doing side quests (fetching data, mutating state)
Containers rendering
nullduring loading without context
Fix Tips:
Keep logic in one place — treat UI like a dumb puppet (no offense)
Use
SkeletonorLoadingcomponents for better UX
🗂️ Folder Structure for Scaling — The Holy Grail
The Problem:
Your Project looks like:
/src
App.jsx
index.js
style.css
SomeRandomComponent.js
backup.js
backup_final2.js
The Solution:
Structure for growth, not chaos:
/src
/components
/Button
index.tsx
styles.module.css
/pages
/Home
index.tsx
/hooks
/utils
/assets
Common Mistakes:
Throwing everything into
/componentsNaming folders like
utils2orhelpers_old
Fix Tips:
Use feature-based structure if your app has many domains
Or stick to Atomic structure for UI-centric apps
Keep one source of truth per component → don’t split logic & styles randomly
♻️ Controlled vs Uncontrolled Components — Who’s the Boss?
The Problem:
Your input field is updating… sometimes. Other times, it refuses to cooperate like a moody cat.
The Solution:
Controlled: State lives in React
Uncontrolled: State lives in the DOM (via
ref)
Controlled:
const [value, setValue] = useState('');
<input value={value} onChange={e => setValue(e.target.value)} />
Uncontrolled:
const ref = useRef();
<input ref={ref} />
Common Mistakes:
Mixing both (React and ref) in the same field = chaos
Forgetting to reset state in forms → haunted by previous input
Fix Tips:
Use controlled when validation/state is needed
Use uncontrolled when you want quick, native-like behavior (e.g., file uploads)
💡 Smart vs Dumb Components — Keep It Simple, Smarty
The Problem:
Everything’s smart. Everything’s stateful. Everything has opinions. Suddenly you can’t reuse anything.
The Solution:
Keep display-only components dumb — pass them data, let them just vibe.
Example:
// Dumb
const ProfileCard = ({ name, img }) => (
<div><img src={img} /><p>{name}</p></div>
);
// Smart
const ProfileContainer = () => {
const { name, img } = useUser();
return <ProfileCard name={name} img={img} />;
};
Common Mistakes:
Dumb components calling APIs
Smart components being 400 lines long
Fix Tips:
Limit smart logic to 1 per feature
Reuse dumb ones like you reuse memes — everywhere
🔁 Render Props & HOCs — Reuse on Expert Mode
The Problem:
You’re duplicating logic like “fetch this”, “track hover“, “handle toggle“ across 10 components.
The Solution:
Abstract logic using:
Render Props (functions as children)
HOCs (higher-order components)
Render Props:
const Toggle = ({ children }) => {
const [on, setOn] = useState(false);
return children({ on, toggle: () => setOn(!on) });
};
<Toggle>
{({ on, toggle }) => (
<button onClick={toggle}>{on ? 'ON' : 'OFF'}</button>
)}
</Toggle>
HOC:
const withUser = (Component) => (props) => {
const user = useUser();
return <Component {...props} user={user} />;
};
Common Mistakes:
Nesting too many HOCs → JSX hell
Forgetting to name HOCs → “Component wrapped in Unknown”
Fix Tips:
Prefer hooks for reuse first. Use render props when state-sharing gets funky.
Keep HOC names clear with
withAuth,withTracking
Wrap-Up: Keep Components Chill
Let’s recap these patterns that (when done right) make your app:
Easy to read
Easy to scale
Easy to hand off to future you (or unlucky teammates)
| Concept | TL;DR |
| Atomic Design | UI in pieces: atoms → pages |
| Presentational vs Container | Split logic and display |
| Folder Structure | Organize before chaos |
| Controlled vs Uncontrolled | Who owns the form input |
| Smart/Dumb Components | Logic vs Display: keep them separate |
| Render Props & HOCs | Reuse patterns for shared logic |
Final Thoughts
A clean component architecture is like a good haircut.
You don’t notice it when it’s done right — but it looks tragic when it’s not.
Want more React hot takes, breakdowns, and rants?
📚 Check out the blog: usefaiaz.hashnode.dev
💻 Code samples: github.com/Faiaz98
Until next time, keep your components small and your renders snappy. Peace✌️


