Skip to main content

Command Palette

Search for a command to run...

React Component Architecture: Clean & Mean

Published
5 min read
React Component Architecture: Clean & Mean
F

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 null during loading without context

Fix Tips:

  • Keep logic in one place — treat UI like a dumb puppet (no offense)

  • Use Skeleton or Loading components 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 /components

  • Naming folders like utils2 or helpers_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)

ConceptTL;DR
Atomic DesignUI in pieces: atoms → pages
Presentational vs ContainerSplit logic and display
Folder StructureOrganize before chaos
Controlled vs UncontrolledWho owns the form input
Smart/Dumb ComponentsLogic vs Display: keep them separate
Render Props & HOCsReuse 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✌️