[React] 리액트 다크모드 적용하기

김현수·2022년 12월 8일
0

styled-components의 공식문서를 보면 테마 구성을 위한 요소로 ThemeProvider 제공

import styled, { ThemeProvider } from 'styled-components'

const Box = styled.div`
  font-size: 1em;
  color: ${props => props.theme.color};
`

// 방식2
const theme = {
  color: "mediumseagreen",
}

render(
  <ThemeProvider theme={{ color: 'mediumseagreen' }}> // 방식1
  <ThemeProvider theme={theme}> // 방식2
    <Box>I'm mediumseagreen!</Box>
  </ThemeProvider>
)

ThemeProvider 의 props로 theme를 전달해주면 그 아래에 있는 모든 component들은 styled 를 사용해 스타일을 정의할 때 이 theme 값을 사용할 수 있다.

theme.js

import styled from "styled-components";

// 반응형 디자인을 위한 픽셀 컨버팅 함수
const pixelToRem = (size) => `${size / 16}rem`; 

// font size를 객체로 반환해주자.
const fontSizes = {
  title: pixelToRem(60),
  subtitle: pixelToRem(30),
  paragraph: pixelToRem(18),
};

// 자주 사용하는 색을 객체로 만들자.
const colors = {
  black: "#000000",
  grey: "#999999",
  green: "#3cb46e",
  blue: "#000080",
};

// 자주 사용하는 스타일 속성을 theme으로 만들어보자.
const common = {
  flexCenter: `
    display: flex;
    justify-contents: center;
    align-items: center;
  `,
  flexCenterColumn: `
    display: flex;
    flex-direction: column;
    justify-contents: center;
    align-items: center;
  `,
};

// theme 객체에 감싸서 반환한다.
const theme = {
  fontSizes,
  colors,
  common,
};

export default theme;

App.js

import React from "react";
import styled, { ThemeProvider } from "styled-components";
import theme from "./theme";

const Container = styled.div`
  width: 100vw;
  height: 100vh;
  ${({ theme }) => theme.common.flexCenterColumn};
`;

const Title = styled.h1`
  font-size: ${({ theme }) => theme.fontSizes.title};
  color: ${({ theme }) => theme.colors.grey};
`;

const Subtitle = styled.h2`
  font-size: ${({ theme }) => theme.fontSizes.subtitle};
  color: ${({ theme }) => theme.colors.green};
`;

const Paragraph = styled.p`
  font-size: ${({ theme }) => theme.fontSizes.Paragraph};
  color: ${({ theme }) => theme.colors.blue};
`;

const App = () => {
  return (
    <div>
      <ThemeProvider theme={theme}>
        <Container>
          <Title>Hello</Title>
          <Subtitle>Welcome to styled-component's world</Subtitle>
          <Paragraph>ThemeProvider에 대해서 배워볼까요?</Paragraph>
        </Container>
      </ThemeProvider>
    </div>
  );
};

export default ThemeProviderPrac;

===============================================

다크모드 구현하기

theme.js

export const lightTheme = {
  bgColor: '#fff',
  textColor: '#222',
  accentColor: '#12cbef',  
};

export const darkTheme = {
  bgColor: '#282c35',
  textColor: '#fff',
  accentColor: '#ffe246',  
};

export const theme = {
  lightTheme,
  darkTheme,
};

export default theme;

App.js

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

const GlobalStyle = createGlobalStyle`
  body {        
    background-color: ${(props) => props.theme.bgColor};
    color:${(props) => props.theme.textColor}
  }  
`;

function App() {
  const [isDarkMode, setIsDarkMode] = useState(false);

// 2. 버튼클릭으로 isDarkMode true<->false
  const toggleDarkMode = () => {
    setIsDarkMode((prev) => !prev);
  };

  return (
    <>// 3. 변화한 isDarkMode 값에 따라 theme 결정
      <ThemeProvider theme={isDarkMode ? darkTheme : lightTheme}>
        <GlobalStyle />  
        <Home isDarkMode={isDarkMode} toggleDarkMode={toggleDarkMode} />
      </ThemeProvider>
    </>
  );
}

export default App;

Home.js

import React from 'react';
import styled from 'styled-components';
import { BsFillSunFill, BsFillMoonFill } from 'react-icons/bs';
...

// 4. theme 적용
const Header = styled.div`
  box-shadow: ${(props) => props.theme.boxShadow};
  border-bottom: ${(props) => props.theme.border};
`;

function Home({ isDarkMode, toggleDarkMode }) {
  return (
    <>
      <header>
        <HeaderLogo className="header__logo">HEO.D.K</HeaderLogo>
        
        // 1. 버튼클릭
        <button
          type="button"
          onClick={toggleDarkMode}
          isDarkMode={isDarkMode}
        >
        // 5. 변화한 isDarkMode 값에 따라 아이콘 결정
          {isDarkMode ? <BsFillSunFill /> : <BsFillMoonFill />}
        </button>
      </header>
      <article>        
        <p>다크모드/라이트 모드</p>        
      </article>
    </>
  );
}

export default Home;

===============================================
추가할 내용 : 로컬스토리지 사용해서 이전 다크/라이트모드 저장

profile
웹개발자

0개의 댓글