UseContext와 UseReducer를 쓰는 이유는,
전역 상태관리 + 상태와 관련된 모든 로직을 컴포넌트간 이동 제약없이 쓸 수 있게끔 하기위해 쓰인다. Context는 사실 UseReducer의 dispatch함수를 전역변수화시키기위해서만 쓰이지는 않는다. 예를 들자면, 어떤 컴포넌트에 뷰를 만드는 로직과 그 정보들이 담겨있었다면 이 변수들을 하나하나 참조해오는거보다 그룹화시켜 전역변수처럼 쓸 수 있게끔 하기 위해 쓰인다.
예를 들면, 다크모드/일반모드를 만들때 변수들을 하나하나 가져와서 바꿔주는게 아닌 한번에 바꿔주기 위해서도 쓰일 수 있다.
UseContext는 새 context를 생성한 곳에서의 Provider로 감싸준 컴포넌트 안에서만 해당 value (dispatch함수)를 가지고 와줄 수 있다.
실제로 다른 컴포넌트에서 이를 쓰고자 할때는 우선
named export된 Dispatch를 가지고와서 해당 컴포넌트에서 useContext함수안에 이 Dispatch를 넣어주어 사용이 가능하다. 여기서 사용 가능한것은 전역 state와 그에 관련된 로직들이다.
반대로, 리액트는 자식 컴포넌트에서 부모 컴포넌트로 state를 올려주지 못하는 단점이 있는데, (함수를 통해 값 정도만 올려줄 수 있다) 이때 자식컴포넌트에서 부모에서부터 온 Context를 업데이트 하게 만들 수도 있다. 그럴 때는 context를 생성할때 메소드를 보낸다.
참고링크: https://ko.reactjs.org/docs/context.html#updating-context-from-a-nested-component
ThemeContext.js
export const themes = {
light: {
foreground: '#000000',
background: '#eeeeee',
},
dark: {
foreground: '#ffffff',
background: '#222222',
},
};
export const ThemeContext = React.createContext({
theme: themes.dark,
toggleTheme: () => {},
});
자식 컴포넌트 ThemeToggleButton.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;
또한, 하나의 자식컴포넌트에서 여러개의 Context를 구독할 수 도 있다.
//기본값이 light인 ThemeContext
const ThemeContext = React.createContext('light');
// 로그인한 유저 정보를 담는 UserContext
const UserContext = React.createContext({
name: 'Guest',
});
class App extends React.Component {
render() {
const {signedInUser, theme} = this.props;
// context 초기값을 제공하는 App 컴포넌트
return (
<ThemeContext.Provider value={theme}>
<UserContext.Provider value={signedInUser}>
<Layout />
</UserContext.Provider>
</ThemeContext.Provider>
);
}
}
function Layout() {
return (
<div>
<Sidebar />
<Content />
</div>
);
}
// 여러 context의 값을 받는 컴포넌트 (Nesting가능)
function Content() {
return (
<ThemeContext.Consumer>
{theme => (
<UserContext.Consumer>
{user => (
<ProfilePage user={user} theme={theme} />
)}
</UserContext.Consumer>
)}
</ThemeContext.Consumer>
);
}