[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 };
};
반응형

BELATED ARTICLES

more