context를 이용하면 단계마다 일일이 props를 넘겨주지 않고도 컴포넌트 트리 전체에 데이터를 제공할 수 있습니다.
일반적인 React 애플리케이션에서 데이터는 위에서 아래로 props를 통해 전달 되지만, 애플리케이션 안의 여러 컴포넌트들에 전해줘야하는 props의 경우 이 과정이 번거로울 수 있습니다. context를 이용하면, 트리 단계마다 명시적으로 props를 넘겨주지 않아도 많은 컴포넌트가 값을 공유하게 할 수 있습니다.
context는 React 컴포넌트 트리 안에서 전역적이라고 볼 수 있는 데이터를 공유 할 수 있도록 고안된 방법입니다. 그러한 데이터로는 현재 로그인한 유저,테마,선호하는 언어 등이 있습니다.
예시코드
최종 선택은 dark테마 입니다.
const ThemeContext = React.createContext('light');
class App extends React.Component {
render() {
return (
<ThemeContext.Provider value="dark">
<Toolbar />
</ThemeContext.Provider>
)
}
}
function Toolbar(props){
return(
<div>
<ThemedButton />
</div>
)
}
class ThemedButton extends React.Component {
static contextType = ThemeContext;
render() {
return <Button theme={this.context} />;
}
React.createContext
const MyContext = React.createContext(defaultValue);
Context 객체를 만듭니다. Context 객체를 구독하고 있는 컴포넌트를 렌더링 할 때 React는 트리 상위에서 가장 가까이 있는 짝이 맞는 Provider로부터 현재값을 읽습니다.
Context.Provider
<MyContext.Provider value={/}/>
Context 오브젝트에 포함된 React 컴포넌트인 Provider는 context를 구독하는 컴포넌트에게 context의 변화를 알리는 역할을 합니다. Provider 컴포넌트는 value prop을 받아서 이 값을 하위에 있는 컴포넌트에게 전달합니다. Provider 하위에서 context를 구독하는 모든 컴포넌트는 Provider의 value prop가 바뀔 때마다 다시 렌더링 됩니다.
Context.Consumer
<MyContext.Consumer>
{value => /* context 값을 이용한 렌더링 */}
</MyContext.Consumer>
이 컴포넌트를 사용하면 함수 컴포넌트안에서 context를 구독할 수 있습니다.
Context.Consumer의 자식은 함수여야합니다. 이 함수는 context의 현재값을 받고 React 노드를 반환합니다. 이 함수가 받는 value 매개변수 값은 해당 context의 Provider 중 상위 트리에서 가장 가까운 Provider의 vlaue prop과 동일합니다. 상위에 Provider가 없다면 value 매개변수 값은 createContext()에 보냈던 defaultValue와 동일할 것입니다.
Context.displayName
Context 객체는 displayName 문자열 속성을 설정할 수 있습니다.
const MyContext = React.createContext()
MyContext.displayName = "MyDisplayName";
<MyContext.Provider> // "MyDisplayName.Provider" in DevTools
<MyContext.Consumer> //"MyDisplayName.Consumer" in DevTools
값이 변하는 context 예시
//theme-context.js
export const themes = {
light: {
foreground: '#000000',
background: '#eeeeee',
},
dark: {
foreground: '#ffffff',
background: '#222222',
},
};
export const ThemeContext = React.createContext(
themes.dark // 기본값
);
//themed-button.js
import {ThemeContext} from "./theme-context";
class ThemedButton extends React.Component {
render(){
let props = this.props;
let theme = this.context;
}
return(
<button
{...props}
style={{backgroundColor: theme.background}
/>
)
}
ThemedButton.contextType = ThemeContext;
export default ThemedButton;
//app.js
import {ThemeContext, themes} from './theme-context';
import ThemedButton from './themed-button';
function Toolbar(props) {
return (
<ThemedButton onClick={props.changeTheme}>
Change Theme
</ThemedButton>
);
}
class App extends React.Component {
constructor(props) {
super(props);
this.state = {
theme: themes.light,
};
this.toggleTheme = () => {
this.setState(state => ({
theme:
state.theme === themes.dark
? themes.light
: themes.dark,
}));
};
render() {
// ThemeProvider 안에 있는 ThemedButton은 state로부터 theme 값을 읽지만
// Provider 밖에 있는 ThemedButton는 기본값인 dark를 사용합니다.
return (
<Page>
<ThemeContext.Provider value={this.state.theme}>
<Toolbar changeTheme={this.toggleTheme} />
</ThemeContext.Provider>
<Section>
<ThemedButton />
</Section>
</Page>
);
}
}}
하위 컴포넌트에서 context 업데이트 하기
//theme-context.js
export const ThemeContext = React.createContext({
theme: themes.dark,
toggleTheme: () => {},
});
//theme-toggler-button.js
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;
//app.js
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 />);
많은 도움이 되었습니다, 감사합니다.