React 16.3 Context API로 테마 전환 구현하기
문제 상황
회사 프로젝트에서 다크모드/라이트모드 전환 기능을 추가해야 했다. 기존에는 Redux로 전역 상태를 관리했는데, 단순 테마 색상 관리에 액션, 리듀서, 커넥트를 모두 작성하는 게 과하다고 느꼈다.
React 16.3에서 정식으로 공개된 Context API가 있다는 걸 알게 되어 적용해보기로 했다.
구현
// ThemeContext.js
import React from 'react';
const themes = {
light: {
background: '#ffffff',
text: '#000000'
},
dark: {
background: '#1a1a1a',
text: '#ffffff'
}
};
const ThemeContext = React.createContext({
theme: themes.light,
toggleTheme: () => {}
});
class ThemeProvider extends React.Component {
state = {
theme: themes.light
};
toggleTheme = () => {
this.setState(prevState => ({
theme: prevState.theme === themes.light ? themes.dark : themes.light
}));
};
render() {
return (
<ThemeContext.Provider
value={{
theme: this.state.theme,
toggleTheme: this.toggleTheme
}}
>
{this.props.children}
</ThemeContext.Provider>
);
}
}
export { ThemeProvider, ThemeContext };
사용하는 쪽에서는 ThemeContext.Consumer로 감싸면 끝이다.
<ThemeContext.Consumer>
{({ theme, toggleTheme }) => (
<div style={{ background: theme.background, color: theme.text }}>
<button onClick={toggleTheme}>테마 전환</button>
</div>
)}
</ThemeContext.Consumer>
결과
Redux 코드 200줄 정도를 60줄로 줄였다. Provider 패턴만 이해하면 되어서 신입 개발자도 금방 파악했다.
다만 Consumer의 render props 패턴이 중첩되면 콜백 지옥이 생길 것 같긴 하다. 작은 단위로 쪼개서 쓰면 괜찮을 듯하다.