styled-components를 사용한 테마 전환

기존 응용 프로그램에 다크 모드 기능을 추가하고 싶다고 가정해 보겠습니다. 스타일이 지정된 구성 요소로 이를 수행하기 위해 ThemeProvider 구성 요소를 사용할 수 있습니다.

기본 예제와 함께 이것을 사용해 보겠습니다. 두 개의 테마 개체를 만들어 보겠습니다. 기본적으로 구성 요소에서 액세스하려는 값이 있는 일반 개체입니다.

// themes.js
export const lightTheme = {
  cardColor: "#ddd",
  textColor: "#000",
}

export const darkTheme = {
  cardColor: "#333",
  textColor: "#fff",
}


두 객체가 동일한 속성을 갖는다는 점을 주목하세요. 테마를 전환할 때 깨지는 것이 없도록 하는 것이 중요합니다. 이는 구성 요소가 속성이 있다고 가정하고 undefined 를 확인할 필요가 없도록 하기 위한 것입니다.

이제 ThemeProvider 를 배치할 위치에 집중해 보겠습니다. 일반적으로 ThemeProvider 의 모든 자손이 테마에 액세스할 수 있기 때문에 일반적으로 트리의 맨 위에 있습니다.

앱의 맨 위에 배치하고 theme 라는 소품을 전달하지만 지금은 lightTheme 개체를 사용하겠습니다.

// app.js
import { ThemeProvider } from "styled-components";
import { lightTheme } from "./themes";

const App = () => {
  return (
    <div>
      <ThemeProvider theme={lightTheme}>
        <Card>
          <p>Hello there!</p>
        </Card>
      </ThemeProvider>
    </div>
  );
}


위의 Card 구성 요소는 작동하는지 테스트할 수 있는 스타일이 지정된 구성 요소일 뿐입니다. Card는 이제 props에서 lightTheme 객체에 액세스할 수 있어야 합니다.

// card.js
import styled from "styled-components";

export const Card = styled.div`
  background-color: ${props => props.theme.cardColor};
  color: ${props => props.theme.textColor};

  padding: 10rem;
  margin: 10rem;
  text-align: center;
`


좋습니다. 이제 설정이 완료되었습니다. 일부 상태 논리를 사용하여 ThemeProvider에 전달된 테마 소품을 변경할 수 있습니다.

// app.js
const App = () => {
  const [theme, setTheme] = useState('light');
  const toggleTheme = () => {
    setTheme(theme === 'light' ? 'dark' : 'light');
  }

  return (
    <div>
      <ThemeProvider 
        theme={theme === 'light' ? lightTheme : darkTheme}
      >
        <Card>
          <div>Hello There!</div>
          <button onClick={toggleTheme}>switch</button>
        </Card>
      </ThemeProvider>
    </div>
  );
}


멋진! 이제 버튼을 클릭할 때마다 테마가 밝게 또는 어둡게 전환됩니다.

그러나 현재 접근 방식에는 몇 가지 문제가 있습니다. 여러 위치에서 테마를 전환하려면 어떻게 해야 할까요? 버튼이 여러 구성 요소보다 깊다면 어떻게 될까요?

이에 대한 간단한 해결책은 React의 useContext 후크를 사용하는 것입니다. 이렇게 하면 모든 하위 항목에서 상태에 액세스하고 설정할 수 있습니다. 조금 리팩토링해서 새로운 컴포넌트를 만들어보자

//theme-context.js
import { darkTheme, lightTheme } from "./themes";
import { useContext, createContext, useState } from "react";


const ThemeContext = createContext();

export const ThemeContextProvider = ({ children }) => {
  const [themeName, setThemeName] = useState('light');
  return (
    <ThemeContext.Provider value={[themeName, setThemeName]}>
      <ThemeProvider theme={themeName === 'light' ? lightTheme : darkTheme }>
        { children }
      </ThemeProvider>
    </ThemeContext.Provider>
  )
}

export const useToggleTheme = () => {
  const [themeName, setThemeName] = useContext(ThemeContext);
  return () => setThemeName(prev => prev === 'light' ? 'dark' : 'light');
}


먼저 createContext를 사용하여 Context 객체를 제공합니다. 이 개체에는 값을 저장하는 구성 요소인 Provider 속성이 있습니다(ThemeProvider가 테마를 저장하는 것처럼).

그런 다음 더 이상 ThemeProvider에 있을 필요가 없기 때문에 App 구성 요소를 여기로 옮겼고 여기에 있는 것이 더 합리적입니다.

Provider 구성 요소는 모든 하위 항목이 값을 사용할 수 있도록 할 수 있습니다. 그러나 액세스할 수 있도록 useToggleTheme 라는 후크를 만들었습니다. 이것은 호출될 때 테마를 밝거나 어둡게 전환하는 함수를 반환합니다.

이제 이 구성 요소를 사용하여 App 에 배치해 보겠습니다.

// app.js
import { Card } from "./card";
import { ThemeContextProvider } from "./theme-context";

const App = () => {
  return (
    <ThemeContextProvider>
      <Card>
        <div>Hello There!</div>
      </Card>
    </ThemeContextProvider>
  );
}


이미 Context에서 처리하고 있기 때문에 모든 논리를 제거할 수 있습니다. 이를 증명하기 위해 버튼을 자체 파일로 이동하고 useToggleTheme 후크를 사용하여 테마를 전환할 수 있습니다.

// button.js
import { useToggleTheme } from "./theme-context"

export const Button = () => {
  const toggleTheme = useToggleTheme();
  return (
    <button onClick={toggleTheme}>Switch</button>
  )
}



// app.js
import { Card } from "./card";
import { Button } from "./button";
import { ThemeContextProvider } from "./theme-context";

const App = () => {
  return (
    <ThemeContextProvider>
      <Card>
        <div>Hello There!</div>
        <Button />
      </Card>
    </ThemeContextProvider>
  );
}


이제 응용 프로그램의 아무 곳에서나 useToggleTheme 후크를 사용하여 테마를 전환할 수 있으며 App 논리를 자체 파일로 리팩토링했습니다.

완성된 모든 파일을 찾을 수 있습니다here.

좋은 웹페이지 즐겨찾기