The Prop Drilling Problem
Prop drilling happens when a value is passed through components that do not use it, only so a deeper child can receive it.
function App() {
const user = { name: "Ava" };
return <Dashboard user={user} />;
}
function Dashboard({ user }) {
return <Sidebar user={user} />;
}
function Sidebar({ user }) {
return <UserMenu user={user} />;
}
function UserMenu({ user }) {
return <p>{user.name}</p>;
}Dashboard and Sidebar may not care about user, but they must keep passing it.
Why It Becomes a Problem
Prop drilling can make code harder to maintain when:
- many intermediate components forward the same props
- renaming a prop requires edits across many files
- unrelated components become coupled to data they do not use
- deeply nested components need app-level values such as theme, auth, or locale
Prop Drilling Is Not Always Bad
Passing props is still the clearest React data flow for local relationships.
function ProductCard({ product }) {
return <ProductPrice price={product.price} />;
}This is normal, readable, and explicit. Do not reach for context just because a prop moves down one or two levels.
Alternatives Before Context
Sometimes component composition removes the problem.
function Dashboard({ userMenu }) {
return <Sidebar userMenu={userMenu} />;
}
function App() {
return <Dashboard userMenu={<UserMenu user={user} />} />;
}The intermediate components no longer need to know about user.
When Context Fits
Context is useful for values that are:
- needed by many components at different depths
- stable enough not to cause constant broad re-renders
- conceptually shared by a section of the app
Examples include current user, theme, locale, feature flags, and route-level settings.
When is prop drilling most likely to become a problem?
Common Mistakes
Do not move every prop into context. Context can hide dependencies and make components harder to reuse.
Do not use context to avoid designing clear component boundaries.
Do not ignore composition. Passing a child element can sometimes be simpler than creating global-ish state.
Practice Challenge
Take a layout with App -> Page -> Sidebar -> UserMenu.
Try three versions:
- pass
userthrough props - pass
<UserMenu />as a composed child - read
userfrom context
Write down which version is clearest and why.
Recap
Prop drilling is a real maintenance problem when intermediate components forward data they do not use. Props are still the default for local data; context is best for genuinely shared values across a tree.