Prop drilling is passing data through props from parent component to child component through multiple nesting levels, even when intermediate components don’t use this data:
// Prop drilling example
function App() {
const user = { name: "John" };
return <Header user={user} />;
}
function Header({ user }) {
return <Navigation user={user} />;
}
function Navigation({ user }) {
return <UserProfile user={user} />;
}Prop drilling is like passing a letter through a chain of people, where each person just passes it along without reading! This is a common problem in React applications. 📮
Prop drilling occurs when data needs to be passed from a top-level component to a deeply nested one through intermediate components:
function App() {
const theme = "dark";
const user = { name: "Anna", role: "admin" };
return <Layout theme={theme} user={user} />;
}
function Layout({ theme, user }) {
return (
<div className={theme}>
<Sidebar user={user} />
</div>
);
}
function Sidebar({ user }) {
return <UserMenu user={user} />;
}
function UserMenu({ user }) {
return <span>Hello, {user.name}!</span>;
}// Components pass props they don't use
function MiddleComponent({ data, onAction, theme, user }) {
return <DeepComponent data={data} onAction={onAction} theme={theme} user={user} />;
}// When changing structure, need to update all intermediate components
function App() {
const newProp = "value"; // Added new prop
return <Level1 existingProp={existingProp} newProp={newProp} />;
}// Component knows about data it doesn't need
function Header({ user, theme, settings, notifications }) {
return <Navigation user={user} theme={theme} settings={settings} />;
}import { createContext, useContext } from 'react';
const UserContext = createContext();
function App() {
const user = { name: "Peter", role: "user" };
return (
<UserContext.Provider value={user}>
<Layout />
</UserContext.Provider>
);
}
function UserMenu() {
const user = useContext(UserContext);
return <span>Hello, {user.name}!</span>;
}function App() {
const user = { name: "Maria" };
return (
<Layout>
<UserMenu user={user} />
</Layout>
);
}
function Layout({ children }) {
return <div className="layout">{children}</div>;
}function useUser() {
return useContext(UserContext);
}
function UserProfile() {
const user = useUser();
return <div>{user.name}</div>;
}// ❌ Prop drilling
function App() {
const theme = "light";
return <Page theme={theme} />;
}
function Page({ theme }) {
return <Button theme={theme} />;
}
// ✅ Context solution
const ThemeContext = createContext();
function App() {
return (
<ThemeContext.Provider value="light">
<Page />
</ThemeContext.Provider>
);
}
function Button() {
const theme = useContext(ThemeContext);
return <button className={theme}>Button</button>;
}// ❌ Passing handlers
function Form() {
const [data, setData] = useState({});
const handleChange = (field, value) => {
setData(prev => ({ ...prev, [field]: value }));
};
return <FormSection onChange={handleChange} />;
}
// ✅ useReducer + Context
const FormContext = createContext();
function Form() {
const [state, dispatch] = useReducer(formReducer, {});
return (
<FormContext.Provider value={{ state, dispatch }}>
<FormSection />
</FormContext.Provider>
);
}// For 1-2 levels might be simpler
function Parent() {
const data = "important data";
return <Child data={data} />;
}
function Child({ data }) {
return <GrandChild data={data} />;
}interface HeaderProps {
user: User;
onLogout: () => void;
}
function Header({ user, onLogout }: HeaderProps) {
return <UserMenu user={user} onLogout={onLogout} />;
}// Redux, Zustand, Jotai
import { useStore } from './store';
function UserProfile() {
const user = useStore(state => state.user);
return <span>{user.name}</span>;
}function UserProvider({ children }) {
const user = { name: "Alex" };
return children(user);
}
function App() {
return (
<UserProvider>
{(user) => <UserProfile user={user} />}
</UserProvider>
);
}❌ Wrong:
// Excessive Context usage
const NameContext = createContext();
const AgeContext = createContext();
const EmailContext = createContext();✅ Correct:
// Group related data
const UserContext = createContext();Prop drilling is a natural problem in React:
Use the right tools for each situation! 🎯