[React] useContext로 다크모드 구현
2022. 2. 13. 18:39
반응형
src/styles/globalStyles.ts
import { createGlobalStyle } from 'styled-components';
import reset from 'styled-reset';
import { Theme } from 'styles/theme';
interface ThemeInterface {
theme: Theme;
}
const GlobalStyle = createGlobalStyle<ThemeInterface>`
${reset}
html,
body {
color: ${({ theme }) => theme.ftColor};
background-color: ${({ theme }) => theme.bgColor};
...
}
`;
export default GlobalStyle;
src/styles/theme.ts
export const lightTheme = {
ftColor: '#010001',
bgColor: '#fdfdfd',
};
export const darkTheme = {
ftColor: '#fdfdfd',
bgColor: '#010001',
};
export type Theme = typeof lightTheme;
App/index.tsx
import React, { createContext } from 'react';
import { Routes, Route } from 'react-router-dom';
import Test from 'components/organisms/Test';
import GlobalStyle from 'styles/globalStyles';
import { lightTheme, darkTheme, Theme } from 'styles/theme';
import { useDarkMode } from 'hooks/useDarkMode';
interface ContextProps {
theme: Theme;
toggleTheme: () => void;
}
//여기서 createContext 해준 걸 나중에 토글버튼에서 useContext로 가져다 쓴다
export const ThemeContext = createContext<ContextProps>({
theme: lightTheme,
toggleTheme: () => {},
});
const App: React.FC = () => {
// useDarkMode는 로컬스토리지에 저장해주는 커스텀훅
const { theme, toggleTheme } = useDarkMode();
return (
<ThemeContext.Provider value={{ theme, toggleTheme }}>
<GlobalStyle theme={theme === lightTheme ? lightTheme : darkTheme} />
<Routes>
<Route path="/" element={<Test />} />
</Routes>
</ThemeContext.Provider>
);
};
export default App;
components/atoms/ToggleButton.tsx (테마 모드를 바꾸는 토글 버튼)
import React, { useContext } from 'react';
import { ThemeContext } from 'App/index';
const ToggleButton: React.FC = () => {
// App/index에서 만든 context다
const { toggleTheme } = useContext(ThemeContext);
return (
<div>
<button type="button" onClick={toggleTheme}>
토글테마
</button>
</div>
);
};
export default ToggleButton;
hooks/useDarkMode.ts
import { useState, useEffect } from 'react';
import { Theme, darkTheme, lightTheme } from 'styles/theme';
export const useDarkMode = () => {
const [theme, setTheme] = useState<Theme>(lightTheme);
const setMode = (mode: Theme) => {
if (mode === lightTheme) {
window.localStorage.setItem('theme', 'light');
} else {
window.localStorage.setItem('theme', 'dark');
}
setTheme(mode);
};
const toggleTheme = () => {
return theme === lightTheme ? setMode(darkTheme) : setMode(lightTheme);
};
const localTheme = window.localStorage.getItem('theme');
useEffect(() => {
if (localTheme !== null) {
if (localTheme === 'dark') {
setTheme(darkTheme);
} else {
setTheme(lightTheme);
}
}
}, [localTheme]);
return { theme, toggleTheme };
};
반응형
'한 걸음 > React & Next.js' 카테고리의 다른 글
[VScode] React snippet(템플릿) 설정으로 반복 타이핑을 피해보자 (0) | 2022.04.18 |
---|---|
스토리북(storybook) 적용하기 (0) | 2022.04.01 |
Numble '다른 색깔 찾기 게임 제작 챌린지' -4 (배포) (0) | 2022.02.13 |
Numble '다른 색깔 찾기 게임 제작 챌린지' -3 (게임 플레이 로직) (0) | 2022.02.12 |
Numble '다른 색깔 찾기 게임 제작 챌린지' -2 (빙고판 구현, random color array 생성) (0) | 2022.02.12 |