icon안동민 개발노트

Context API를 사용한 테마 변경 기능 구현


 이 실습에서는 Context API와 useReducer 훅을 활용하여 애플리케이션의 테마를 동적으로 변경할 수 있는 기능을 구현해보겠습니다.

 이 과정을 통해 전역 상태 관리와 컴포넌트 간 데이터 공유 방법을 실제로 경험할 수 있습니다.

1단계 : 프로젝트 설정

 먼저 새로운 React 프로젝트를 생성합니다.

npx create-react-app theme-switcher
cd theme-switcher

2단계 : 테마 Context 생성

 src 폴더에 ThemeContext.js 파일을 생성하고 다음 내용을 작성합니다.

src/ThemeContext.js
import React, { createContext, useContext, useReducer } from 'react';
 
// 초기 테마 상태
const initialState = {
  theme: 'light',
};
 
// 테마 변경을 위한 액션 타입
const TOGGLE_THEME = 'TOGGLE_THEME';
 
// Reducer 함수
function themeReducer(state, action) {
  switch (action.type) {
    case TOGGLE_THEME:
      return { theme: state.theme === 'light' ? 'dark' : 'light' };
    default:
      return state;
  }
}
 
// Context 생성
const ThemeContext = createContext();
 
// Provider 컴포넌트
export function ThemeProvider({ children }) {
  const [state, dispatch] = useReducer(themeReducer, initialState);
 
  // 테마 전환 함수
  const toggleTheme = () => {
    dispatch({ type: TOGGLE_THEME });
  };
 
  return (
    <ThemeContext.Provider value={{ theme: state.theme, toggleTheme }}>
      {children}
    </ThemeContext.Provider>
  );
}
 
// 커스텀 훅: 테마 상태와 함수를 쉽게 사용할 수 있게 함
export function useTheme() {
  const context = useContext(ThemeContext);
  if (context === undefined) {
    throw new Error('useTheme must be used within a ThemeProvider');
  }
  return context;
}

 이 코드에서,

  • themeReducer 함수는 현재 테마 상태와 액션을 받아 새로운 테마 상태를 반환합니다.
  • ThemeProvider 컴포넌트는 useReducer를 사용하여 테마 상태를 관리하고, 이를 Context를 통해 자식 컴포넌트에 제공합니다.
  • useTheme 커스텀 훅은 컴포넌트에서 테마 상태와 toggleTheme 함수를 쉽게 사용할 수 있게 해줍니다.

3단계 : App 컴포넌트 수정

 src/App.js 파일을 수정하여 ThemeProvider를 적용하고 테마에 따른 스타일을 적용합니다.

src/App.js
import React from 'react';
import { ThemeProvider, useTheme } from './ThemeContext';
import './App.css';
 
function App() {
  return (
    <ThemeProvider>
      <div className="App">
        <Header />
        <MainContent />
      </div>
    </ThemeProvider>
  );
}
 
function Header() {
  const { theme, toggleTheme } = useTheme();
  return (
    <header className={`header ${theme}`}>
      <h1>Theme Switcher</h1>
      <button onClick={toggleTheme}>Toggle Theme</button>
    </header>
  );
}
 
function MainContent() {
  const { theme } = useTheme();
  return (
    <main className={`main ${theme}`}>
      <p>This is the main content. The current theme is: {theme}</p>
    </main>
  );
}
 
export default App;

4단계 : CSS 스타일 적용

 src/App.css 파일을 수정하여 라이트 테마와 다크 테마에 대한 스타일을 정의합니다.

src/App.css
.App {
  text-align: center;
  min-height: 100vh;
  transition: all 0.3s ease;
}
 
.header {
  padding: 20px;
  transition: all 0.3s ease;
}
 
.main {
  padding: 20px;
  transition: all 0.3s ease;
}
 
.light {
  background-color: #f0f0f0;
  color: #333;
}
 
.dark {
  background-color: #333;
  color: #f0f0f0;
}
 
button {
  padding: 10px 20px;
  font-size: 16px;
  cursor: pointer;
}

5단계 : 실행 및 테스트

 이제 애플리케이션을 실행하고 테마 변경 기능을 테스트할 수 있습니다.

npm start

 브라우저에서 애플리케이션을 열고 "Toggle Theme" 버튼을 클릭하여 테마가 변경되는 것을 확인합니다.

코드 설명

 1. ThemeContext.js

  • createContext를 사용하여 ThemeContext를 생성합니다.
  • useReducer를 사용하여 테마 상태를 관리합니다.
  • ThemeProvider 컴포넌트는 Context의 Provider 역할을 하며, 전체 애플리케이션에 테마 상태와 toggleTheme 함수를 제공합니다.
  • useTheme 커스텀 훅은 다른 컴포넌트에서 테마 관련 기능을 쉽게 사용할 수 있게 해줍니다.

 2. App.js

  • ThemeProvider로 전체 애플리케이션을 감싸 테마 기능을 모든 컴포넌트에서 사용할 수 있게 합니다.
  • Header 컴포넌트에서는 useTheme 훅을 사용하여 현재 테마를 가져오고 테마 전환 버튼을 구현합니다.
  • MainContent 컴포넌트에서도 useTheme 훅을 사용하여 현재 테마에 따른 스타일을 적용합니다.

 3. App.css

  • 라이트 테마와 다크 테마에 대한 스타일을 정의합니다.
  • transition 속성을 사용하여 테마 전환 시 부드러운 효과를 줍니다.

작동 방식

  1. 사용자가 "Toggle Theme" 버튼을 클릭합니다.
  2. toggleTheme 함수가 호출되어 TOGGLE_THEME 액션을 dispatch합니다.
  3. themeReducer가 현재 상태와 액션을 바탕으로 새로운 테마 상태를 계산합니다.
  4. 새로운 테마 상태가 Context를 통해 모든 하위 컴포넌트에 전파됩니다.
  5. 테마를 사용하는 컴포넌트들(Header, MainContent)이 자동으로 리렌더링되어 새로운 테마를 적용합니다.

확장 가능성

 이 실습에서 구현한 테마 변경 기능은 다음과 같이 확장할 수 있습니다.

  1. 다양한 테마 지원 : 'light'와 'dark' 외에 다른 테마 옵션을 추가할 수 있습니다.
  2. 테마 설정 저장 : 로컬 스토리지를 사용하여 사용자의 테마 선호도를 저장하고 불러올 수 있습니다.
  3. 자동 테마 전환 : 시스템 설정이나 시간에 따라 자동으로 테마를 전환하는 기능을 추가할 수 있습니다.

 이 실습을 통해 Context API와 useReducer를 사용하여 전역 상태를 관리하고, 이를 애플리케이션 전체에 적용하는 방법을 배웠습니다.

 이러한 패턴은 테마 변경뿐만 아니라 사용자 인증, 언어 설정, 애플리케이션 설정 등 다양한 전역 상태 관리에 활용할 수 있습니다.

 Context API와 useReducer의 조합은 많은 경우에 Redux와 같은 별도의 상태 관리 라이브러리 없이도 효과적인 상태 관리 솔루션을 제공합니다.

 특히 중소 규모의 애플리케이션에서는 이 방식만으로도 충분한 경우가 많습니다.

 하지만 애플리케이션의 규모가 커지고 상태 관리가 더욱 복잡해진다면, Redux나 MobX와 같은 전용 상태 관리 라이브러리의 사용을 고려해볼 수 있습니다.

 이러한 라이브러리들은 더 강력한 개발자 도구, 미들웨어 지원, 그리고 대규모 애플리케이션을 위한 최적화된 성능을 제공합니다.