React 16.3 Context API로 Props Drilling 해결하기
문제 상황
사용자 인증 정보를 최상위 App 컴포넌트에서 관리하고 있었는데, 이를 사용하는 하위 컴포넌트가 5~6단계 깊이에 위치해 있었다. 중간 컴포넌트들은 해당 props를 사용하지 않으면서도 단순히 전달만 하는 역할을 했다.
// 기존 방식
<App user={user}>
<Layout user={user}>
<Content user={user}>
<Sidebar user={user}>
<UserProfile user={user} />
중간에 컴포넌트가 추가되거나 구조가 변경될 때마다 props 전달 체인을 수정해야 했고, 실수로 누락하면 디버깅이 어려웠다.
Context API 도입
React 16.3에서 새로 출시된 Context API는 이전 버전의 실험적 기능에서 정식 API로 승격되었다. React.createContext를 사용해 구현했다.
// UserContext.js
import React from 'react';
const UserContext = React.createContext(null);
export const UserProvider = UserContext.Provider;
export const UserConsumer = UserContext.Consumer;
export default UserContext;
// App.js
import { UserProvider } from './UserContext';
class App extends Component {
state = { user: null };
componentDidMount() {
fetchUser().then(user => this.setState({ user }));
}
render() {
return (
<UserProvider value={this.state.user}>
<Layout>
<Content>
<Sidebar />
</Content>
</Layout>
</UserProvider>
);
}
}
// UserProfile.js
import { UserConsumer } from './UserContext';
const UserProfile = () => (
<UserConsumer>
{user => user ? <div>{user.name}</div> : <div>로그인 필요</div>}
</UserConsumer>
);
결과
중간 컴포넌트들이 user props를 전달할 필요가 없어졌고, 새로운 컴포넌트에서 사용자 정보가 필요할 때 UserConsumer만 추가하면 됐다. 코드 가독성이 개선되고 리팩토링 시 실수 가능성이 줄어들었다.
다만 Consumer의 render props 패턴이 중첩되면 가독성이 떨어지는 문제가 있어, 전역 상태 관리가 필요한 경우엔 여전히 Redux를 사용하고 있다.