Emotion 으로 Dark Mode 설정하기

HYl·2022년 3월 29일
2

Emotion 으로 Dark Mode를 설정을 해보았다. TypeScript 에 아직 익숙치 않아서 Type 지정을 하는 데에 시간이 많이 소요된 것 같다, 문법 공부를 다시 해야할 것 같다.

우선은 이 part에서는 Dark Mode를 구현하는 것에 집중하기로 했다.

결과물


theme.ts

import { DarkTheme, LightTheme } from '@emotion/react';

export const lightTheme: LightTheme = {
  mode: {
    text: '#000',
    background: '#fff',
    buttonText: '#000',
    buttonTextHover: '#fff',
    buttonBorder: '#000',
    buttonBg: 'rgba(0, 0, 0, 0)',
    buttonBgHover: 'rgba(0, 0, 0, 1)',
  },
};

export const darkTheme: DarkTheme = {
  mode: {
    text: '#fff',
    background: '#121212',
    buttonText: '#fff',
    buttonTextHover: '#000',
    buttonBorder: '#fff',
    buttonBg: 'rgba(255, 255, 255, 0)',
    buttonBgHover: 'rgba(255, 255, 255, 1)',
  },
};

lightTheme와 darkTheme 으로 나누어서 color 색상을 지정하였다.

theme.d.ts

import '@emotion/react';

declare module '@emotion/react' {
  export interface LightTheme {
    mode: {
      text: string;
      background: string;
      buttonText: string;
      buttonTextHover: string;
      buttonBorder: string;
      buttonBg: string;
      buttonBgHover: string;
    };
  }

  export interface DarkTheme {
    mode: {
      text: string;
      background: string;
      buttonText: string;
      buttonTextHover: string;
      buttonBorder: string;
      buttonBg: string;
      buttonBgHover: string;
    };
  }
}

theme를 사용할 때 반드시 type을 지정해주어야 한다.


global.tsx

import React from 'react';
import { Global, css, LightTheme, DarkTheme } from '@emotion/react';

const style = (theme: any) => css`
  * {
    margin: 0;
    padding: 0;
    -moz-osx-font-smoothing: grayscale;
    -webkit-font-smoothing: antialiased;
    box-sizing: border-box;
  }

  body {
    color: ${theme.mode.text};
    background: ${theme.mode.background};
  }
`;

const GlobalStyle = () => {
  return <Global styles={style} />;
};

export default GlobalStyle;

이 부분을 구현할 때 아쉬웠던 점은, theme 를 변수로 받아올 때 any 로 지정을 한 점이다.
type ColorMode = LightTheme | DarkTheme; 를 변수로 지정한 다음
any 대신 ColorMode 로 Type을 선언하고 싶었지만 밑의 style 에서 에러 메시지가 작동하여, 이 부분에서 에러메시지를 구글링 하다가 못 찾아서 우선 any 로 Type을 지정해두었다.

추후에 수정 할 예정이다.

type ColorMode = LightTheme | DarkTheme;

const style = (theme: ColorMode) => css`
	...
`;

const GlobalStyle = () => {
  return <Global styles={style} />;
};

export default GlobalStyle;

오류 해결

다시 살펴보니, Type 선언 시에, interface 를 LightTheme 와 DarkTheme 두 가지로 나누었던 것이 에러의 근본 원인이었다. 동일한 내용의 Interface를 굳이 쪼개어서 선언한 것이었다 .. 🤦‍♀️

type을 any 대신 Theme로 지정해줄 수 있게 되었다 .. !


const style = (theme: Theme) => css`
	...
`;

const GlobalStyle = () => {
  return <Global styles={style} />;
};

export default GlobalStyle;

오류 해결 Commit 내역


App.tsx

import React, { useState } from 'react';
import { BrowserRouter } from 'react-router-dom';

import { ThemeProvider } from '@emotion/react';

import GlobalStyle from '@src/styles/global';
import Routes from '@src/Routes';
import { darkTheme, lightTheme } from '@src/styles/theme';

const App = () => {
  const [isDark, setIsDark] = useState(false);

  return (
    <BrowserRouter>
      <ThemeProvider theme={isDark ? darkTheme : lightTheme}>
        <GlobalStyle />
        <Routes isDark={isDark} setIsDark={setIsDark} />
      </ThemeProvider>
    </BrowserRouter>
  );
};

export default App;

Routes.tsx

/** @jsx jsx */
import { css, jsx } from '@emotion/react';
import React, { Dispatch, SetStateAction } from 'react';
import { Route } from 'react-router-dom';
import Home from './pages/Home';

interface RoutesProps {
  isDark: boolean;
  setIsDark: Dispatch<SetStateAction<boolean>>;
}

const Routes: React.FC<RoutesProps> = ({ isDark, setIsDark }) => {
  return (
    <div>
      <button
        css={css`
          color: ${isDark ? 'white' : 'black'};
        `}
        onClick={() => {
          setIsDark(!isDark);
        }}
      >
        {isDark ? 'dark' : 'light'}버튼 입니다.
      </button>
      <Route exact path="/" component={Home} />
    </div>
  );
};

export default Routes;
profile
꾸준히 새로운 것을 알아가는 것을 좋아합니다.

0개의 댓글