Prop drilling — это передача данных через пропсы от родительского компонента к дочернему через несколько уровней вложенности, даже если промежуточные компоненты не используют эти данные:
// Пример prop drilling
function App() {
const user = { name: "Иван" };
return <Header user={user} />;
}
function Header({ user }) {
return <Navigation user={user} />;
}
function Navigation({ user }) {
return <UserProfile user={user} />;
}Prop drilling — это как передача письма через цепочку людей, где каждый просто передаёт его дальше, не читая! Это распространённая проблема в React-приложениях. 📮
Prop drilling возникает, когда данные нужно передать от верхнего компонента к глубоко вложенному через промежуточные компоненты:
function App() {
const theme = "dark";
const user = { name: "Анна", 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>Привет, {user.name}!</span>;
}// Компоненты передают пропсы, которые не используют
function MiddleComponent({ data, onAction, theme, user }) {
return <DeepComponent data={data} onAction={onAction} theme={theme} user={user} />;
}// При изменении структуры нужно обновлять все промежуточные компоненты
function App() {
const newProp = "value"; // Добавили новый проп
return <Level1 existingProp={existingProp} newProp={newProp} />;
}// Компонент знает о данных, которые ему не нужны
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: "Петр", role: "user" };
return (
<UserContext.Provider value={user}>
<Layout />
</UserContext.Provider>
);
}
function UserMenu() {
const user = useContext(UserContext);
return <span>Привет, {user.name}!</span>;
}function App() {
const user = { name: "Мария" };
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 решение
const ThemeContext = createContext();
function App() {
return (
<ThemeContext.Provider value="light">
<Page />
</ThemeContext.Provider>
);
}
function Button() {
const theme = useContext(ThemeContext);
return <button className={theme}>Кнопка</button>;
}// ❌ Передача обработчиков
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>
);
}// Для 1-2 уровней может быть проще
function Parent() {
const 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: "Олег" };
return children(user);
}
function App() {
return (
<UserProvider>
{(user) => <UserProfile user={user} />}
</UserProvider>
);
}❌ Неправильно:
// Избыточное использование Context
const NameContext = createContext();
const AgeContext = createContext();
const EmailContext = createContext();✅ Правильно:
// Группировка связанных данных
const UserContext = createContext();Prop drilling — естественная проблема в React:
Используйте правильные инструменты для каждой ситуации! 🎯