Що таке "prop drilling"?
Визначення
Prop drilling - це процес, при якому дані (props) передаються вниз по дереву компонентів через декілька проміжних рівнів, які самі ці дані не використовують, а просто "пробрасують далі".
Простий приклад
Припустимо, у тебе є структура:
<App>
└── <Parent>
└── <Child>
└── <Grandchild>Ти хочеш передати дані з App -> в Grandchild.
Без контексту (через props):
function Grandchild({ user }) {
return <p>Привіт, {user.name}!</p>;
}
function Child({ user }) {
return <Grandchild user={user} />;
}
function Parent({ user }) {
return <Child user={user} />;
}
export default function App() {
const user = { name: "Tim" };
return <Parent user={user} />;
}Тут Parent і Child не використовують user взагалі,
вони просто пробрасують його далі.
Це і є prop drilling.
Чому це погано
| Проблема | Що відбувається |
|---|---|
| Шум у коді | Кожен проміжний компонент змушений мати зайві props |
| Складно підтримувати | При зміні структури - потрібно змінювати всі рівні |
| Знижується ізоляція | Компоненти стають залежні від даних, яких не використовують |
| Перевикористовуваність падає | "Дурні" компоненти змушені знати про непотрібні props |
| Важко читати | "Ланцюжок" пропсів ускладнює розуміння логіки застосунку |
Ілюстрація
App
├── user (зберігається тут)
↓
Parent
↓
Child
↓
Grandchild (використовує)Все дерево "просвердлене" пропсами зверху вниз - звідси і термін "drilling" (свердління).
Приклад ближчий до реального
<App>
<Navbar />
<Sidebar />
<Main>
<PostList>
<PostCard user={user} />
</PostList>
</Main>
</App>Якщо user потрібен тільки в PostCard, але його потрібно передавати через Main і PostList - це вже prop drilling hell.
Як вирішити проблему prop drilling
1. React Context API
Найстандартніший спосіб позбутися свердління - створити "глобальне джерело даних".
import { createContext, useContext } from "react";
const UserContext = createContext(null);
function Grandchild() {
const user = useContext(UserContext);
return <p>Привіт, {user.name}!</p>;
}
function App() {
const user = { name: "Tim" };
return (
<UserContext.Provider value={user}>
<Grandchild />
</UserContext.Provider>
);
}Тепер Grandchild отримує user напряму з контексту,
а не через ланцюжок props.
2. State management (Redux, Zustand, Jotai, Recoil)
Якщо даних багато, і вони потрібні в різних частинах застосунку - краще винести їх у глобальне сховище:
// store.js (приклад із Zustand)
import { create } from "zustand";
export const useUserStore = create(set => ({
user: { name: "Tim" },
setUser: (user) => set({ user }),
}));
// Grandchild.jsx
import { useUserStore } from "./store";
function Grandchild() {
const user = useUserStore(state => state.user);
return <p>Привіт, {user.name}!</p>;
}Тепер не потрібно "свердлити" пропси - дані доступні з будь-якого компонента.
3. Custom hooks
Якщо контекст або Zustand - "важка зброя", можна просто зробити кастомний хук, щоб сховати передачу:
function useUser() {
const [user, setUser] = useState({ name: "Tim" });
return { user, setUser };
}
function App() {
const userStore = useUser();
return <Parent userStore={userStore} />;
}
function Grandchild({ userStore }) {
const { user } = userStore;
return <p>{user.name}</p>;
}Чистіше, ніж передавати кожен окремий prop, але prop drilling залишається - просто спрощений.
4. Композиція замість props
Іноді можна передати компоненти напряму через children:
function Layout({ header, footer }) {
return (
<div>
<header>{header}</header>
<main>Контент</main>
<footer>{footer}</footer>
</div>
);
}
function App() {
return (
<Layout
header={<Header user={{ name: "Tim" }} />}
footer={<Footer />}
/>
);
}Це не прибирає prop drilling глобально, але робить передачу даних локальною і більш керованою.
Коли prop drilling допустимий
Не завжди потрібно уникати його будь-якою ціною.
Якщо дерево компонентів неглибоке (1-2 рівні). Якщо prop потрібен тільки трохи нижче. Якщо даних небагато і вони рідко змінюються.
Контекст і стор - потрібні, коли проблема системна, а не випадкова.
Підсумок
| Критерій | Prop drilling |
|---|---|
| Що це | Передача props через ланцюжок проміжних компонентів |
| Чому погано | Забруднює код, знижує ізоляцію і перевикористовуваність |
| Коли допустимо | Для неглибоких і простих випадків |
| Як вирішувати | Context API, Zustand, Redux, custom hooks |
| Головне правило | "Якщо prop проходить через більше ніж 2 рівні - задумайся про контекст" |
Головна ідея:
Prop drilling - це коли дані просвердлюються через зайві компоненти. Рішення - винести джерело даних вище і дати до нього прямий доступ.
Коротка відповідь
Для співбесідиКоротка відповідь допоможе вам впевнено відповідати на цю тему під час співбесіди.