Front-end 코드 작성 시 props가 너무 깊게 내려가거나, 중간 컴포넌트는 쓰지 않지만 props만 패스하는 경우가 있을 수 있습니다.
이 문제의 이름이 바로 Prop Drilling입니다.
Prop Drilling
Prop Drilling이란, 부모 컴포넌트에서 자식 → 손자 → 증손자… 이런 식으로
데이터(props)를 계속 전달해야 하는 현상을 말합니다.
// App.tsx
function App() {
const user = { name: '유향', age: 27 };
return <Parent user={user} />;
}
// Parent.tsx
function Parent({ user }: { user: { name: string; age: number } }) {
return <Child user={user} />;
}
// Child.tsx
function Child({ user }: { user: { name: string; age: number } }) {
return <GrandChild user={user} />;
}
// GrandChild.tsx
function GrandChild({ user }: { user: { name: string; age: number } }) {
return <div>{user.name}님 안녕하세요!</div>;
}
- 이 예제에서 실제로 user를 사용하는 건 마지막 GrandChild 뿐이지만, 중간의 Parent와 Child도 그 데이터를 전달하기 위해 props를 계속 이어가야 하죠.
- 이것이 바로 Prop Drilling 문제입니다.
왜 문제가 될까?
| 문제점 | 설명 |
| 유지보수성 저하 | 중간 컴포넌트가 많을수록 props 수정 시 모든 단계에서 변경 필요 |
| 불필요한 리렌더링 | 상위 데이터 변경 시, 전달만 하는 중간 컴포넌트까지 리렌더링됨 |
| 가독성 저하 | 데이터 흐름을 추적하기 어려워짐 |
- 결국 컴포넌트 구조가 커질수록 코드의 복잡도가 급격히 올라갑니다.
해결책 1 — 조합(Composition) 패턴 활용
조합(Composition) 패턴을 사용하면 부모 컴포넌트가 자식 컴포넌트에 Props를 일일이 전달해야 하는 Prop Drilling 문제를 완화할 수 있어요.
더 나아가, 조합 패턴은 불필요한 중간 추상화를 제거하여 개발자가 각 컴포넌트의 역할과 의도를 보다 명확하게 이해할 수 있도록 돕습니다.
function ItemEditModal({ open, items, recommendedItems, onConfirm, onClose }) {
const [keyword, setKeyword] = useState("");
return (
<Modal open={open} onClose={onClose}>
<ItemEditBody
keyword={keyword}
onKeywordChange={setKeyword}
onClose={onClose}
>
<ItemEditList
keyword={keyword}
items={items}
recommendedItems={recommendedItems}
onConfirm={onConfirm}
/>
</ItemEditBody>
</Modal>
);
}
function ItemEditBody({ children, keyword, onKeywordChange, onClose }) {
return (
<>
<div style={{ display: "flex", justifyContent: "space-between" }}>
<Input
value={keyword}
onChange={(e) => onKeywordChange(e.target.value)}
/>
<Button onClick={onClose}>닫기</Button>
</div>
{children}
</>
);
}
- 위의 예시처럼 children을 사용해 필요한 컴포넌트를 부모에서 작성하도록 하면 불필요한 Props Drilling을 줄일 수 있습니다.
- 하지만, 조합 패턴만으로는 해결되지 않는 경우도 있고, 컴포넌트 트리 구조가 깊어지면 여전히 문제가 발생할 수 있어요.
- 위의 예시에서도 ItemEditModal 컴포넌트는 여전히 items와 recommendedItems를 Props Drilling하고 있죠.
해결책 2 — Context API
Context API는 React에서 제공하는 전역 상태 공유 도구입니다.
중간 컴포넌트를 거치지 않고도, 필요한 하위 컴포넌트들이 바로 데이터에 접근할 수 있죠.
import React, { createContext, useContext } from 'react';
// 1 Context 생성
const UserContext = createContext<{ name: string } | null>(null);
// 2️ Provider로 감싸서 user 값 공유
function App() {
const user = { name: '유향' };
return (
<UserContext.Provider value={user}>
<Parent />
</UserContext.Provider>
);
}
// 3️ 중간 컴포넌트는 props 필요 없음
function Parent() {
return <Child />;
}
function Child() {
return <GrandChild />;
}
// 4️ 필요한 곳(GrandChild)에서 useContext로 바로 접근
function GrandChild() {
const user = useContext(UserContext);
return <h2>안녕하세요, {user?.name}님!</h2>;
}
- 이제 어디서든 접근할 수 있습니다.
- 이렇게 하면 더 이상 props를 전달할 필요가 없습니다.
Composition vs Context API — 언제 어떤 걸 쓸까?
| 상황 | 추천 |
| 특정 하위 컴포넌트만 데이터가 필요함 | Composition 패턴 |
| 여러 계층에서 공통 상태를 써야 함 | Context API |
| 상태 변화가 거의 없는 정적 데이터 | Composition (성능 손해 없음) |
| 자주 바뀌는 전역 상태 | Context (또는 Redux, Zustand 등) |
'개발 공부' 카테고리의 다른 글
| Prisma 스키마 (2) - 인덱스, 유니크, 복합키 (0) | 2025.11.01 |
|---|---|
| Prisma 스키마 (1) (0) | 2025.10.31 |
| DFS, BFS (0) | 2025.10.08 |
| Getter, Setter (0) | 2025.09.30 |
| onAnimationStart, onShow (0) | 2025.09.28 |