일반적인 React 애플리케이션에서 데이터는 위에서 아래로 props를 통해 전달된다.
하지만 언어나 테마같이 여러 컴포넌트에 전해줘야하는 props가 있을 경우, 이 과정이 번거로울 수 있다. (props drilling 발생..)
이때 context를 이용하면, 트리 구조에서 단계마다 props를 넘겨주지 않아도 많은 컴포넌트가 값을 공유하도록 할 수 있다.
Context - React
context는 React 컴포넌트 트리 안에서 전역적(global)인 값을 공유할 수 있도록 고안된 방법이다.
e.g. 현재 로그인한 유저, 사용자가 선호하는 언어, 테마 등..
예를 들어, 아래의 코드는 버튼 컴포넌트를 꾸미기 위해 테마 props를 명시적으로 3단계나 넘겨주고 있다.
class App extends React.Component {
render() {
return <Toolbar theme='dark' /> // props 1차 전달
}
}
function Toolbar(props) {
return (
<div>
<ThemeButon theme={props.theme} /> // props 2차 전달
</div>
);
}
class ThemeButton extends React.Component {
render() {
return <Button theme={this.props.theme} /> // props 3차 전달
}
}
위의 코드에서 context를 사용하면, props를 전달하지 않고 아래처럼 작성할 수 있다.
const ThemeContext = React.createContext('light'); // createContext() 메소드로 context를 생성할 수 있다.
class App extends React.Component {
render() {
return (
<ThemeContext.Provider value='dark'> // Provider를 이용해 하위 트리의 모든 컴포넌트에 테마 값을 보내줄 수 있다.
<Toolbar /> // props 전달 X
</ThemeContext.Provider>
);
}
}
function Toolbar() {
return (
<div>
<ThemeButon /> // props 전달 X
</div>
);
}
class ThemeButton extends React.Component {
static contextType = ThemeContext; // 가장 가까이 있는 Provider를 찾아 값를 읽어온다.
render() {
return <Button theme={this.context} /> // 'dark'
}
}
React.createContext()
: Context 객체를 만드는 메소드
defaultValue
가 쓰인다.const ThemeContext = React.createContext('light');
<Context.Provider>
: context를 구독하는 컴포넌트들에게 context의 변화를 알리는 역할을 하는 React 컴포넌트
value
prop을 받아서 이 값을 하위 컴포넌트들에게 전달한다.value
prop이 바뀔 때마다 다시 렌더링된다.<ThemeContext.Provider value='dark'>
<하위 컴포넌트>
</ThemeContext.Provider>
Class.contextType
: React.createContext()
로 생성한 Context 객체를 원하는 클래스의 contextType
프로퍼티로 지정할 수 있다.
this.context
로 해당 Context의 값을 읽을 수 있다. (이때 가장 가까운 Provider를 찾아 값을 읽어온다.)class ThemeButton extends React.Component {
static contextType = ThemeContext; // ThemeButton 클래스의 contextType 프로퍼티로 ThemeContext 객체를 지정
render() {
let value = this.context;
/* context 값을 이용한 렌더링 */
}
}
render()
를 포함한 모든 컴포넌트 생명주기 메소드에서 활용할 수 있다.class ThemeButton extends React.Component {
componentDidMount() {
/* context 값을 이용한 코드 */
}
componentDidUpdate() {
/* ... */
}
componentWillUnmount() {
/* ... */
}
render() {
let value = this.context;
}
}
ThemeButton.contextType = ThemeContext; // ThemeButton 클래스의 contextType 프로퍼티로 ThemeContext 객체를 지정
<Context.Consumer>
: context 변화를 구독하는 React 컴포넌트
이 컴포넌트를 사용하면 함수 컴포넌트 안에서 context를 구독할 수 있다.
Context.Consumer
의 자식은 함수여야 하며, 이 함수는 context의 현재값을 받고 React 노드를 반환한다.<ThemeContext.Consumer>
{value => <함수 컴포넌트 value={value} />}
</ThemeContext.Consumer>
Context.displayName
: Context 객체는 displayName
이라는 문자열 속성을 설정할 수 있다.
React 개발자 도구는 이 문자열을 사용해서 context를 어떻게 보여줄지 결정한다.
const ThemeContext = React.createContext('light');
ThemeContext.displayName = 'ColorTheme';
<ThemeContext.Provider> // 'ColorTheme.Provider' in DevTools
<ThemeContext.Consumer> // 'ColorTheme.Consumer' in DevTools
context의 주된 용도는 다양한 레벨에 네스팅된 많은 컴포넌트에게 데이터를 전달하는 것이다.
단순히 props drilling을 대체하기 위해 context를 사용해서는 안된다. context를 사용하면 컴포넌트를 재사용하기 어려워지기 때문이다. 따라서 꼭 필요할 때만 사용해야한다. props drilling을 해결하기 위해서는 컴포넌트 합성을 사용하는 것이 좋다.
항상 깔끔한 정리네요 컨텍스트 api 개념 다시 정리하고 갑니다