깊은 곳에 있는 자식에게 값을 주려고 중간 컴포넌트들이 필요도 없는 props를 계속 넘기던 번거로움, 이제 끝낼 수 있어요. 이번 장은 props 드릴링 문제 → Context로 해결하는 흐름을 아주 천천히 따라갑니다.
지금까지 데이터는 부모 → 자식 한 방향으로 props를 통해 내려줬어요(CH 05). 그런데 만약 데이터를 아주 깊은 곳에 있는 자식이 필요로 한다면 어떻게 될까요? 중간에 있는 컴포넌트들은 자기는 그 값을 쓰지도 않으면서, 오직 아래로 전달만 하려고 props를 계속 받아 넘겨야 해요.
이렇게 중간 컴포넌트들이 필요도 없는 props를 단지 전달만 하려고 줄줄이 넘기는 현상을 props 드릴링(props drilling)이라고 불러요. "드릴로 층층이 뚫고 내려간다"는 느낌의 이름이에요.
user라는 값을 만들었어요.user를 써요. 진짜 필요한 곳은 여기뿐!user)를 보내고 싶어요. 그런데 직접 못 주고 Page → Layout을 거쳐야 해요. Page와 Layout은 소포 내용물이 필요 없는데도 "나 몰라, 그냥 아래로 전달만 할게" 하며 계속 손에서 손으로 넘겨야 하죠.
전달 단계가 3~4겹만 돼도 코드가 지저분해지고, 중간에 props 이름 하나 바꾸면 여러 파일을 다 고쳐야 해요.
Context(컨텍스트)는 여러 컴포넌트가 함께 쓰는 값을 "전역 통로"로 만들어 두는 리액트 기능이에요. 통로에 값을 한 번 올려두면, 중간 단계를 일일이 거치지 않고 필요한 자식이 통로에서 바로 꺼내 쓸 수 있어요.
createContextcreateContext(기본값)로 Context 객체를 하나 만들어요. 이게 "전역 통로"예요. 괄호 안의 값은 Provider로 감싸지 않았을 때 쓰이는 기본값이에요.<Context.Provider><ThemeContext.Provider value={공유값}>로 자식들을 감싸요. value에 넣은 값이 통로에 흐르고, 이 Provider 안쪽에 있는 모든 자손이 그 값을 읽을 수 있게 돼요.useContextconst v = useContext(ThemeContext)라고 쓰면, 통로에 흐르던 value 값을 바로 꺼내 써요. props로 안 받아도 돼요!이제 세 단계를 하나의 예제로 이어볼게요. "테마(다크/라이트)" 값을 공유하는 흔한 예예요.
import { createContext, useContext } from "react";
// ① 통로 만들기 (기본값 "light")
const ThemeContext = createContext("light");
function App() {
// ② Provider로 감싸고, value에 공유할 값을 올림
return (
<ThemeContext.Provider value="dark">
<Page />
</ThemeContext.Provider>
);
}
// 중간 컴포넌트들은 theme를 몰라도 됨 (props 전달 불필요!)
function Page() {
return <Layout />;
}
function Layout() {
return <Avatar />;
}
// ③ 필요한 자식이 통로에서 바로 꺼내 읽음
function Avatar() {
const theme = useContext(ThemeContext); // "dark"
return <p>현재 테마: {theme}</p>;
}
createContext(기본값) — 통로(Context 객체)를 만든다. (딱 한 번)<Context.Provider value={값}> — 통로에 값을 흘려보내고, 그 값을 받을 자식들을 감싼다.useContext(Context) — 자식에서 통로의 값을 꺼내 읽는 훅.
기억법: 만들고(create) → 감싸고(Provider) → 꺼낸다(useContext).
useContext 하나예요. const 값 = useContext(만든Context객체) 형태로 쓰고, 인자로는 createContext로 만든 그 객체를 넘겨요. 문자열 이름이 아니라 객체 자체를 넘긴다는 점에 주의!Context는 "앱의 아주 많은 곳에서 필요로 하는 전역적인 값"에 잘 맞아요. 대표적인 예를 볼게요.
| 잘 맞는 예 | 왜 Context가 어울리나 |
|---|---|
| 🎨 테마(다크/라이트) | 거의 모든 컴포넌트가 색·스타일을 위해 테마를 알아야 해서. |
| 👤 로그인 사용자 정보 | 헤더·프로필·설정 등 여러 곳에서 현재 사용자를 참조해서. |
| 🌍 언어 설정(i18n) | 모든 텍스트가 선택된 언어를 알아야 번역돼서. (i18n = internationalization의 약자, "국제화") |
value가 바뀌면 그 값을 읽는 모든 컴포넌트가 다시 렌더링돼요. 자주 바뀌는 값을 큰 통로에 몽땅 담으면 리렌더가 과하게 일어나 성능이 나빠질 수 있어요.
판단 기준: "정말 많은 곳에서 공유하고, 자주 안 바뀌는 전역 값"일 때만 Context. 아니면 props로 충분해요.
전역 값을 다루는 방법에는 Context 말고도 Zustand · Redux 같은 상태관리 라이브러리가 있어요(CH 01 생태계에서 잠깐 봤죠). Context는 리액트에 기본 내장되어 있고 가벼운 대신, 복잡하고 자주 바뀌는 대형 상태를 다루기엔 기능이 단출해요.