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 패턴이 중첩되면 콜백 지옥이 생길 것 같긴 하다. 작은 단위로 쪼개서 쓰면 괜찮을 듯하다.

React 16.3 Context API로 테마 전환 구현하기