🌗 Styled Components로 라이트/다크 모드 전환하기

    실제 프로젝트에서는 사용자에게 다크 모드와 라이트 모드를 제공하는 것이 중요한 UX 요소 중 하나이다.

    styled-components와 ThemeProvider를 활용하면 전역 테마 전환을 매우 간단하게 구현할 수 있다.


    ✅ 1. 테마 객체 정의하기

    // themes.js
    export const lightTheme = {
      textColor: "#111",
      backgroundColor: "whitesmoke",
    };
    
    export const darkTheme = {
      textColor: "whitesmoke",
      backgroundColor: "#111",
    };
    

    ✅ 2. App에서 테마 상태 관리

    여러개의 property를 가진 객체를 두개 (다크/라이트) 설정함으로써 간편하게 theme을 바꿀 수 있다. 

     

    // App.js
    import React, { useState } from "react";
    import styled, { ThemeProvider } from "styled-components";
    import { lightTheme, darkTheme } from "./themes";
    
    const Title = styled.h1`
      color: ${(props) => props.theme.textColor};
    `;
    
    const Wrapper = styled.div`
      display: flex;
      flex-direction: column;
      gap: 20px;
      height: 100vh;
      width: 100vw;
      justify-content: center;
      align-items: center;
      background-color: ${(props) => props.theme.backgroundColor};
      transition: all 0.3s ease-in-out;
    `;
    
    const ToggleButton = styled.button`
      padding: 10px 20px;
      font-weight: bold;
      border: none;
      cursor: pointer;
      background-color: ${(props) => props.theme.textColor};
      color: ${(props) => props.theme.backgroundColor};
      border-radius: 8px;
    `;
    
    function App() {
      const [isDark, setIsDark] = useState(true);
      const toggleTheme = () => setIsDark((prev) => !prev);
    
      return (
        <ThemeProvider theme={isDark ? darkTheme : lightTheme}>
          <Wrapper>
            <Title>{isDark ? "Dark Mode" : "Light Mode"}</Title>
            <ToggleButton onClick={toggleTheme}>
              Toggle Theme
            </ToggleButton>
          </Wrapper>
        </ThemeProvider>
      );
    }
    
    export default App;

    ✅ 결과 화면

    • 기본은 다크 모드 (isDark = true)
    • 버튼을 누르면 라이트 모드로 전환됨
    • ThemeProvider는 상태에 따라 lightTheme 또는 darkTheme을 전달


    🔧 ThemeProvider 작동 원리

    ✅ 1. React Context를 기반으로 동작한다

    styled-components의 ThemeProvider는 내부적으로 React Context API를 사용해 테마를 관리한다.

     
    <ThemeProvider theme={currentTheme}> 
    	<App /> 
    </ThemeProvider>
     

    이렇게 감싸면 ThemeProvider는 theme 객체를 Context로 저장하고, 하위의 모든 styled component는 그 값을 props.theme을 통해 자동으로 주입받는다.


    ✅ 2. styled-components는 내부적으로 ThemeContext를 사용한다

    styled-components는 ThemeContext라는 내부 컨텍스트를 만들고, ThemeProvider로 전달받은 theme을 여기에 저장한다.

    // (내부적으로는 대략 이런 형태) 
    const ThemeContext = React.createContext(defaultTheme); 
    export const ThemeProvider = ({ theme, children }) => { 
    	return <ThemeContext.Provider value={theme}>{children}</ThemeContext.Provider>; 
    };
     

    ✅ 3. styled component는 theme context에 접근하여 props.theme으로 넣어준다

    모든 styled 컴포넌트는 생성될 때 ThemeContext를 자동으로 구독하고, 렌더링 시 theme 값을 props.theme으로 넣어준다.

    const Title = styled.h1` 
    	color: ${(props) => props.theme.textColor}; 
    `;

    → 여기서 props.theme.textColor는 ThemeProvider를 통해 전달된 값이다.
    → 만약 ThemeProvider가 없으면 props.theme는 undefined다.

     

    ✅ 일단 styled-component 로 한번 만들어보긴 했지만.. 

    • localStorage에 사용자의 테마 선호 저장하여 유지하기
    • 시스템 설정에 따른 다크모드 자동 적용 (window.matchMedia)

    실유저가 있는 서비스에서는 위의 두가지 방법으로 구현하는게 좋을듯. 


    React + Styled-components로 구현한 테마 시스템은 확장성도 좋고, 유지보수도 쉽다.
    다크모드 버튼을 넣고 싶다면 이 구조를 기반으로 시작해보자!

     

    반응형

    댓글