해당 포스트를 좀 더 보완한 useContext를 이용하여 다크모드 적용하는 것을 따로 포스팅했으니

참고하면 좋을 것 같다🧑‍🔧

gingerkang.tistory.com/101

 

[React] TypeScript와 useContext로 다크모드 적용

Context? Context는 리액트에서 데이터를 전역적으로 관리해야할 때 사용한다. 자주 쓰이는 예로는 현재 로그인한 유저, 테마 등이 있다. 앞서 언급한 대로 Context는전역(Global)값이고, 여러 단계로 nest

gingerkang.tistory.com

 

React + Styled Components

일단 styled-components를 설치해주자.

 

yarn add styled-components

 

 

그리고 해야할 일은 프로젝트 내에 src 폴더에 global-styles.ts 파일과 theme.ts 파일을 만들어 주는 것이다.두 파일을 만들었으면 아래의 코드를 참고하여 입맛대로 설정을 해준다.

 

theme.ts 

// theme.ts

export const lightTheme = {
  bgColor: '#ffffff',
  textColor: '#000000',
  toggleBorder: '#FFF',
  gradient: 'linear-gradient(#39598A, #79D7ED)',
}

export const darkTheme = {
  bgColor: '#060606',
  textColor: '#FFFFFF',
  toggleBorder: '#6B8096',
  gradient: 'linear-gradient(#091236, #1E215D)',
}

export const theme = {
  lightTheme,
  darkTheme,
}

export default theme;

 

global-styles.ts

// global-styles.ts

import { createGlobalStyle } from 'styled-components';
import reset from 'styled-reset';

export const GlobalStyle = createGlobalStyle`
    ${reset}
    * {
    	margin: 0;
        padding: 0;
        box-sizing: border-box;
    }
    body {
        align-items: center;
        background: ${({theme} : {theme: any}) => theme.bgColor};
        display: flex;
        flex-direction: column;
        justify-content: center;
        height: 100vh;
        margin: 0;
        padding: 0;
        transition: all 0.25s linear;
        color: ${({theme} : {theme: any}) => theme.textColor};
    }
    button { 
        cursor: pointer;
        border: none;
        outline: none;
        color: ${({theme} : {theme: any}) => theme.bgColor};
        background-color: ${({theme} : {theme: any}) => theme.textColor};
    }
`;

 

TypeScript 기준으로 해서 JavaScript 환경에서 코드를 작성하면 에러가 날 것이다. JavaScript 환경에서는 타입 설정을 해줄 필요가 없기 때문에 바로 사용한다.

 

// JavaScript

color: ${({ theme }) => theme.textColor};
background: ${({ theme }) => theme.bgColor};

 

 

그리고 App.tsx 파일로 가서 컴포넌트들에 GlobalStyle 적용을 해주고 ThemeProvider로 감싸줄 것이다. ThemeProvider Wrapper로 감싸주고 아래와 같이 theme를 넘겨주면 자식 컴포넌트에서 theme객체를 사용할 수 있게 된다. 

 

App.tsx

// App.tsx

import React from 'react';
import { ThemeProvider } from 'styled-components';
import { lightTheme, darkTheme } from './theme';
import { GlobalStyle } from './global-styles';

function App() {
  return (
    <ThemeProvider theme={lightTheme}>
      <>
        <GlobalStyle />
        <button>Dark Mode</button>
      </>
    </ThemeProvider>
  );
}

export default App;

 

여기까지 하면 아래와 같이 못생긴 녀석이 화면에 나타난다. 다음은 버튼을 누르면 모드가 바뀌게 toggle 설정을 해줄 차례이다.

 

 

App.tsx

// App.tsx

import React, { useState } from "react";
import { ThemeProvider } from "styled-components";
import { lightTheme, darkTheme } from "./theme";
import { GlobalStyle } from "./global-styles";

function App() {
  const [theme, setTheme] = useState("dark");

  const isLight = theme === "light";

  const toggleTheme = () => {
    if (theme === "light") {
      setTheme("dark");
    } else {
      setTheme("light");
    }
  };

  return (
    <ThemeProvider theme={theme === "light" ? lightTheme : darkTheme}>
      <>
        <GlobalStyle />
        <button onClick={toggleTheme}>Dark Mode</button>
      </>
    </ThemeProvider>
  );
}

export default App;

 

이렇게 하면 Dark Mode라는 버튼을 누를 때 마다 light modedark mode로 바뀌는 것을 볼 수 있다.

이제 버튼 스타일링을 해보자. buttonstyled-componentsDarkModeToggleButton으로 선언한다.

 

App.tsx

// App.tsx

...

const DarkModeToggleButton = styled.button`
  background: ${({ theme } : { theme: any }) => theme.gradient};
  border: 2px solid ${({ theme } : { theme: any }) => theme.toggleBorder};
  border-radius: 30px;
  cursor: pointer;
  display: flex;
  font-size: 0.5rem;
  justify-content: space-between;
  margin: 0 auto;
  overflow: hidden;
  padding: 0.5rem;
  position: relative;
  width: 8rem;
  height: 4rem;

  svg {
    height: auto;
    width: 2.5rem;
    transition: all 0.3s linear;
    
    // sun
    &:first-child {
      transform: ${({ isLight } : { isLight: any }) => isLight ? 'translateY(0)' : 'translateY(100px)'};
    }
    
    // moon
    &:nth-child(2) {
      transform: ${({ isLight } : { isLight: any }) => isLight ? 'translateY(-100px)' : 'translateY(0)'};
    }
  }
`;

function App() {
	...

 

 

JavaScript의 경우 아래와 같이 작성한다.

 

// JavaScript

background: ${({ theme }) => theme.gradient};
border: 2px solid ${({ theme }) => theme.toggleBorder};

 

그리고 App.tsx 파일에서 렌더링 하는 return 내에 다음과 같이 작성해준다.

 

// App.tsx

function App() {
  ...
  
  return (
    <ThemeProvider theme={theme === "light" ? lightTheme : darkTheme}>
      <>
        <GlobalStyle />
        <DarkModeToggleButton isLight={isLight}>
            <img src={LightMode} alt='sun' onClick={toggleTheme}/>
            <img src={DarkMode} alt='moon' onClick={toggleTheme}/>
        </DarkModeToggleButton>
      </>
    </ThemeProvider>
  );
}

 

 

 

 


생강강

,