

위의 사진과 같이 버튼을 클릭하면
전역 배경색상이 변경되는 토글 테마 기능을 구현해보겠다.
가장 먼저 사용할 테마를 정의해준다.
// Theme.tsx
export type ThemeName = 'light' | 'dark';
export type ColorKey = 'primary' | 'background';
interface Theme {
name: ThemeName;
color: Record<ColorKey, string>;
}
// 밝은 테마
export const light: Theme = {
name: 'light',
color: {
primary: 'brown',
background: 'lightgrey',
},
};
// 어두운 테마
export const dark: Theme = {
name: 'dark',
color: {
primary: 'coral',
background: 'brown',
},
};
// 테마를 변경 시
export const getTheme = (themeName: ThemeName): Theme => {
switch (themeName) {
case 'light':
return light;
case 'dark':
return dark;
}
};
여담으로 Record 유틸리티를 처음 알게 되었다.
사용방법은 Record<K, T>로 키유형 K에 타입을 지정해주면된다.
위의 코드에 경우 ColorKey('primary','background')는 string 타입을 가진다는 뜻
1번에서 정의한 Theme를 관리할 Context와 Provider를 생성해준다.
참고로 Provider는 제공자라는 영단어 뜻처럼 Context API에서 전역 상태나 데이터를 제공하는 역할을 해준다.
// ThemeContext.tsx
interface State {
themeName: ThemeName;
toggleTheme: () => void;
}
export const state = {
themeName: 'light' as ThemeName,
toggleTheme: () => {},
};
export const ThemeContext = createContext<State>(state);
지정해준 테마(themeName)와 색상을 변경해줄 (toggleTheme)를 관리할
Context를 생성해준다.
// ThemeContext.tsx
export const PageTurnerThemeProvider = ({children}: {children: ReactNode}) => {
const [themeName, setThemeName] = useState<ThemeName>('light');
const toggleTheme = () => {
setThemeName(
themeName === 'light' ? 'dark' : 'light',
);
return (
<ThemeContext.Provider value={{themeName, toggleTheme}}>
<ThemeProvider theme={getTheme(themeName)}>
<GlobalStyle themeName={themeName} />
{children}
</ThemeProvider>
</ThemeContext.Provider>
);
};
PageTurnerThemeProvider 컴포넌트로 테마 상태를 관리하고 하위 컴포넌트에 테마 정보를 제공한다.
색상을 변경해주는 toggleTheme()를 여기서 구현해준다.
return값에 전체를 ThemeContext.Provider로 감싸 하위 컴포넌트에
themeName, toggleTheme을 전달하고
ThemeProvider에서 현재 테마에 맞는 색상을 적용한다.
지금까지 작업한 테마를 모든 컴포넌트에 적용할 것이기 때문에
App.tsx로 가서 전체를 위에서 만든 PageTurnerThemeProvider로 감싸주면 된다.
// App.tsx
function App() {
return (
<PageTurnerThemeProvider>
<ThemeSwitcher /> // 4번에서 구현할 예정
<Home />
</PageTurnerThemeProvider>
);
}
이제 우리의 목표인 토글 테마 기능을 구현해주면 된다.
// ThemeSwitcher
const ThemeSwitcher = () => {
const {themeName, toggleTheme} = useContext(ThemeContext);
return <button onClick={toggleTheme}>{themeName}</button>;
};
2번에서 작업한 Context를 가져와서 이곳에서 사용해준다.
Context API는 많이 사용해보지 않아서 아직 어색한 감이 있다
지금은 비교적 간단한 작업이라 헷갈리지 않았지만
Provider 위치나 Context 구조를 명확하게 하여 혼동을 방지해야겠다는
생각이 든다.