props drilling을 방지하기 위한 react 자체 api 이다.
context를 사용하면 컴포넌트 트리 전체에 데이터를 제공할 수 있다.
context의 주된 용도는 다양한 레벨에 네스팅된 많은 컴포넌트에게 데이터를 전달하는 것이다.
context를 사용하면 컴포넌트를 재사용하기가 어려워지니 꼭 필요할 때만 써야한다.
const MyContext = React.createContext(defaultValue);
context 객체를 만든다.
defaultValue 매개변수는 트리 안에서 적절한 Provider를 찾지 못했을 때만 쓰이는 값이다.
Provider를 통해 undefined를 보내도 구독 컴포넌트들은 undefined 를 읽고 defaultValue를 읽지 않는다.
<MyContext.Provider value={/* 어떤 값 */}>
React.createContext를 통해 만들어진 context 객체에 포함된 React 컴포넌트인 Provider는 context를 구독하는 컴포넌트들에게 context의 변화를 알린다.
Provider 하위에서 context를 구독하는 모든 컴포넌트들은 Provider의 value prop이 바뀔 때 마다 새로 렌더링 된다.
<MyContext.Consumer>
{value => /* context 값을 이용한 렌더링 */}
</MyContext.Consumer>
context의 변화를 구독하는 React 컴포넌트이다.
Context.Consumer 컴포넌트는 함수 컴포넌트에서 context를 구독하기 위해 사용된다.
Context.Consumer 의 자식은 함수여야한다.
자식인 함수는 context의 현재값을 받고 React 노드를 반환한다.
이 자식놈의 함수가 받는 value가 Provider가 제공하는 value다.
상위에 Provider가 없다면 defaultValue다.
// createContext에 보내는 기본값의 모양을
// 하위 컴포넌트가 받고 있는 매개변수 모양과 동일하게 만드는 것 잊지마세요!
export const ThemeContext = React.createContext({
theme: themes.dark,
toggleTheme: () => {},
});
import {ThemeContext} from './theme-context';
function ThemeTogglerButton() {
// ThemeTogglerButton는 context로부터
// theme 값과 함께 toggleTheme 매서드도 받고 있습니다.
return (
<ThemeContext.Consumer>
{({theme, toggleTheme}) => (
<button
onClick={toggleTheme}
style={{backgroundColor: theme.background}}>
Toggle Theme
</button>
)}
</ThemeContext.Consumer>
);
}
export default ThemeTogglerButton;
import {ThemeContext, themes} from './theme-context';
import ThemeTogglerButton from './theme-toggler-button';
class App extends React.Component {
constructor(props) {
super(props);
this.toggleTheme = () => {
this.setState(state => ({
theme:
state.theme === themes.dark
? themes.light
: themes.dark,
}));
};
// state에 업데이트 메서드도 포함되어있으므로
// 이 또한 context Provider를 통해 전달될것입니다.
this.state = {
theme: themes.light,
toggleTheme: this.toggleTheme,
};
}
render() {
// Provider에 state 전체를 넘겨줍니다.
return (
<ThemeContext.Provider value={this.state}>
<Content />
</ThemeContext.Provider>
);
}
}
function Content() {
return (
<div>
<ThemeTogglerButton />
</div>
);
}
const root = ReactDOM.createRoot(
document.getElementById('root')
);
root.render(<App />);