Dumb Components (aka Presentational Components)

//Button.tsx
function Button({ label, onClick }) {
  return <button onClick={onClick}>{label}</button>;
}

//UserCard.tsx
function UserCard({ name, age }) {
  return (
    <div>
      <h2>{name}</h2>
      <p>Age: {age}</p>
    </div>
  );
}

These components are “dumb” because they don’t manage data; they just render props.

Smart Components (aka Container Components)

//UserList.tsx
import { useState, useEffect } from "react";
import UserCard from "./UserCard"; // dumb component

function UserList() {
  const [users, setUsers] = useState([]);

  useEffect(() => {
    fetch("/api/users")
      .then(res => res.json())
      .then(data => setUsers(data));
  }, []);

  return (
    <div>
      {users.map(user => (
        <UserCard key={user.id} name={user.name} age={user.age} />
      ))}
    </div>
  );
}

UserList is smart, it fetches data and manages state, but delegates UI to dumb components.

Why even use this pattern?

Note. Modern React with hooks sometimes blurs the line, because even “dumb” components can use hooks for local state. The idea is more about responsibility and separation of concerns than strictly whether a component has state.