Context API
손쉬운 컴포넌트 상태 공유
props, callback의 문제
React의 데이터 흐름은 "단방향(One Way) 하향식"입니다. 위에서 아래로 props
를 전달하고, 아래에서 callback
을 실행해 전달 받은 상태를 업데이트 합니다. 문제는 컴포넌트 트리가 복잡해지면 상태 관리가 매우 어려워집니다.

뿐만 아니라, props
를 아래 방향으로 한 단계씩 전달 ▸ 전달 해야 하기 때문에 불필요하게 중간에서 전달 받아 다시 아래 방향으로 전달하는 경우도 빈번하게 발생하게 됩니다.

문제 상황을 이해하기 위해 다음의 예시 코드를 살펴봅니다. Z, A, B는 각각 App, MenuBar, SignIn 컴포넌트입니다.
// Z(App)가 인증 정보를 B(SignIn)에게 전달하기 위해
// A(MenuBar)에게 인증 정보를 전달 함.
class App extends React.Component {
state = {
authentification: true
}
render() {
return (
<div className="app">
<MenuBar isAuth={this.state.authentification} />
{/* ... */}
</div>
)
}
}
// A(MenuBar)는 인증 정보가 필요 없지만,
// B(SignIn)에게 전달해야 함.
const MenuBar = props => (
<div className="menubar">
<SignIn isAuth={props.isAuth} />
{/* ... */}
</div>
)
// A(MenuBar)를 거쳐 Z(App)가 전달한
// 인증 정보를 힘겹게 받은 B(SignIn)
const SignIn = props => {
const signed = props.isAuth
if (signed) {
return <div className="signed">로그인 사용자</div>
} else {
return <div className="un-signed">로그인 되지 않음</div>
}
}
컨텍스트(Context) 활용
React는 복잡한 컴포넌트 트리의 "상태 공유 문제를 해결하기 위한 방법"으로 컨텍스트(Context) API를 제공합니다. Context API를 사용하면 상위 컴포넌트에서 하위에 종속된 모든 컴포넌트에 데이터를 공급(Provider)한 후, 특정 위치의 컴포넌트에서 바로 수요(Consumer) 하도록 설정할 수 있습니다.

Context를 통한 데이터 "공급", "수요"의 의미가 아직은 모호하게 느껴질 수 있습니다. 아래 예시 코드를 살펴보면 그 모호함이 다소 해소될 수 있을 것입니다.
// 컨텍스트 생성.
const AuthContext = React.createContext();
// -------------------------------------------------------------
class App extends React.Component {
state = {
authentification: true
}
render() {
// AuthContext.Provider 요소를 사용해
// 인증 정보를 값(value)으로 공급
const value = { ...this.state }
return (
<div className="app">
<AuthContext.Provider value={value}>
<MenuBar />
{/* ... */}
</AuthContext.Provider>
</div>
)
}
}
const MenuBar = () => (
<div className="menubar">
<SignIn isAuth={props.isAuth} />
{/* ... */}
</div>
)
// AuthContext.Consumer를 통해 전달 받은
// 값(value)을 사용해 렌더링.
const SignIn = () => (
<AuthContext.Consumer>
{
(context) => context ?
<div className="signed">로그인 사용자</div> :
<div className="un-signed">로그인 되지 않음</div>
}
</AuthContext.Consumer>
)
Context의 주된 사용 목적은 복잡하게 "중첩 된" 하위 컴포넌트(들)에 데이터를 공유하는 것입니다. Context를 사용하면 컴포넌트 재사용이 어려우므로 꼭 필요한 경우에만 사용합니다. (참고)
컨텍스트 생성(create)
React.createContext API를 사용해 컨텍스트를 생성할 수 있습니다.
const Context = React.createContext();
컨텍스트 공급자(Provider)
생성된 컨텍스트 객체는 Provider 요소를 포함합니다. Provider는 중첩된 하위 컴포넌트(들)에게 value
를 공급합니다.
<Context.Provider value={value}>
{/* 중첩된 컴포넌트 */}
<NestedComponent />
</Context.Provider>
컨텍스트 수요자(Consumer)
생성된 컨텍스트 객체의 Consumer 요소는 공급받은 value
를 전달 받는 콜백 함수를 통해 컴포넌트를 렌더링합니다.
<Context.Consumer>
{
(context) => {
// React 요소 반환
return <></>
}
}
</Context.Consumer>
컨텍스트 타입(Type)
클래스 컴포넌트의 contextType
스태틱(Static) 속성에 컨텍스트 객체를 설정하면 this.context
를 통해 컨텍스트 객체의 값을 읽고 사용할 수 있습니다.
import Context from '../contexts/Context'
class ClassComponent extends React.Component {
static contextType = AuthContext
render() {
// 컨텍스트의 value 읽기
console.log(this.context)
return <></>
}
}
이 방법은 클래스 컴포넌트에서만 사용 가능합니다. 함수 컴포넌트는 다른 방법을 사용합니다.
컨텍스트 타입을 사용하면 단 하나의 컨텍스트 객체만 사용 가능합니다. 하나 이상의 컨텍스트 객체를 사용하려면 앞서 살펴 본 Context.Consumer를 중첩해 사용해야 합니다. (참고)
컨텍스트 기본값 설정
생성 된 컨텍스트 객체에 기본값을 설정할 수 있습니다. 예를 들어 라이트(light), 다크(dark) 테마의 컬러 정보를 컨텍스트에서 공급하고자 할 수 있습니다. 그런 경우 다음과 같이 테마 정보 객체를 컨텍스트 생성 과정에 전달합니다.
// 테마 정보 객체
const themes = {
light: {
fg: '#1c2739',
bg: '#fcfcfc'
},
dark: {
fg: '#fcfcfc',
bg: '#1c2739'
}
}
// 테마 컨텍스트 생성
const ThemeContext = React.createContext(
themes.dark // 기본값 설정
)
export default ThemeContext
아래 코드는 컨텍스트 타입을 통해 컨텍스트의 기본 값을 Button 컴포넌트의 theme
속성으로 전달합니다.
Last updated
Was this helpful?