React

ThemeProvider๋ฅผ ์™œ ์‚ฌ์šฉํ• ๊นŒ? ๐Ÿง

Dana10 2025. 2. 13. 23:28

 

ํŒ€ ํ”„๋กœ์ ํŠธ๋ฅผ ์ง„ํ–‰ํ•˜๋ฉฐ ๊ณตํ†ต color๋ฅผ ์ •์˜ํ•ด ๋†“๊ณ  ์“ฐ๊ธฐ๋กœ ํ•˜์˜€๋‹ค.

์šฐ๋ฆฌ ํŒ€์€ styled-components๋ฅผ ์‚ฌ์šฉํ•˜๊ณ  ์žˆ๋Š”๋ฐ

๊ตฌ๊ธ€๋ง์„ ํ†ตํ•ด ThemeProvider๋ฅผ ํ†ตํ•ด ์ „์—ญ์—์„œ ๊ณต์œ ํ•  ์ˆ˜ ์žˆ๋‹ค๋Š” ๋‚ด์šฉ์„ ์ ‘ํ•˜๊ณ  ๋ฐ”๋กœ ์ ์šฉํ•ด ๋ณด๊ธฐ๋กœ ํ–ˆ๋‹ค.

import { StrictMode } from 'react';
import { createRoot } from 'react-dom/client';
import App from './App.jsx';
import { ThemeProvider } from 'styled-components';
import { theme } from './styles/theme.js';

createRoot(document.getElementById('root')).render(
  <StrictMode>
    <ThemeProvider theme={theme}>
      <App />
    </ThemeProvider>
  </StrictMode>
);

 

์ตœ์ƒ๋‹จ์—์„œ <ThemeProvider>๋กœ children์„ ๊ฐ์ŒŒ๋‹ค.

๊ทธ๋Ÿฐ๋ฐ ๊ฐ‘์ž๊ธฐ ๋“  ์˜๋ฌธ.. 

์–ด์จŒ๋“  theme.js ์ž์ฒด๋ฅผ export ํ–ˆ๊ณ 

์‚ฌ์šฉ์ฒ˜์—์„œ importํ•ด์„œ ํ•„์š”ํ•  ๋•Œ ๋ฐ”๋กœ๋ฐ”๋กœ ์‚ฌ์šฉํ•  ์ˆ˜๋„ ์žˆ๋Š” ๊ฑฐ ์•„๋‹Œ๊ฐ€?

์ƒ‰์ƒ์„ ๋ณ€๊ฒฝํ•œ๋‹ค๊ณ  ํ•˜๋”๋ผ๋„ theme.js ์•ˆ์— ์ฝ”๋“œ๋ฅผ ์ˆ˜์ •ํ•˜๋‹ˆ๊นŒ ์‚ฌ์šฉํ•˜๊ณ  ์žˆ๋Š” ๊ณณ์€ ๋‹ค ๊ฐ™์ด ์ˆ˜์ •๋  ๊ฑฐ ์•„๋ƒ?

๊ทผ๋ฐ ์™œ ๊ตณ์ด ThemProvider๋ฅผ ์จ์•ผํ•˜์ง€..? ๐Ÿค”

 

๊ทธ๋ž˜์„œ ThemeProvider๋ฅผ ์‚ฌ์šฉํ•ด์•ผ ํ•˜๋Š” ์ด์œ ๋ฅผ ์ฐพ์•„๋ดค๋‹ค.


 

โœจ ThemeProvider๋ฅผ ์‚ฌ์šฉํ•˜๋Š” ์ด์œ 


1.  React Context ํ™œ์šฉ

ThemeProvider๋Š” ๋‚ด๋ถ€์ ์œผ๋กœ React Context API๋ฅผ ํ™œ์šฉํ•œ๋‹ค.

๋”ฐ๋ผ์„œ ์ปดํฌ๋„ŒํŠธ ํŠธ๋ฆฌ ๋‚ด์˜ ๋ชจ๋“  ์ž์‹ ์ปดํฌ๋„ŒํŠธ๋“ค์—๊ฒŒ ์ž๋™์œผ๋กœ ๊ฐ’์„ ์ „๋‹ฌํ•  ์ˆ˜ ์žˆ๋‹ค.

์ด๋ฅผ ํ†ตํ•ด์„œ ํ•˜์œ„ ์ปดํฌ๋„ŒํŠธ๋“ค์€ theme.js ํŒŒ์ผ์„ ์ผ์ผ์ด importํ•˜์ง€ ์•Š์•„๋„ ์‰ฝ๊ฒŒ theme์— ์ ‘๊ทผํ•˜์—ฌ ๊ฐ’์„ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๋‹ค.

2.  ๋™์  ํ…Œ๋งˆ ๋ณ€๊ฒฝ

ThemeProvider๋ฅผ ์‚ฌ์šฉํ•˜๋ฉด ๋™์ ์œผ๋กœ ํ…Œ๋งˆ๋ฅผ ์‰ฝ๊ฒŒ ๋ณ€๊ฒฝํ•  ์ˆ˜ ์žˆ๋‹ค.

์˜ˆ๋ฅผ ๋“ค์–ด ๋‹คํฌ ๋ชจ๋“œ / ๋ผ์ดํŠธ ๋ชจ๋“œ๋ฅผ ์ „ํ™”ํ•˜๊ณ  ์‹ถ๋‹ค๋ฉด ThemeProvider์˜ theme์˜ ๊ฐ’์„ ๋™์ ์œผ๋กœ ๋ณ€๊ฒฝํ•  ์ˆ˜ ์žˆ๋‹ค.

์ด ๋ณ€๊ฒฝ์ด ์ž๋™์œผ๋กœ ๋ชจ๋“  ์ž์‹ ์ปดํฌ๋„ŒํŠธ์— ์ ์šฉ๋˜๊ธฐ ๋•Œ๋ฌธ์—

ํ…Œ๋งˆ๋ฅผ ๋ณ€๊ฒฝํ•  ๋•Œ importํ•œ theme.js๋ฅผ ์ผ์ผ์ด ์ˆ˜์ •ํ•  ํ•„์š” ์—†์ด ์ปดํฌ๋„ŒํŠธ ์ƒํƒœ๋‚˜ ์ปจํ…์ŠคํŠธ๋ฅผ ํ†ตํ•ด ์‰ฝ๊ฒŒ ์ ์šฉํ•  ์ˆ˜ ์žˆ๋‹ค.

 

3. ํ…Œ๋งˆ ๊ฐ’ ๊ด€๋ฆฌ์˜ ์ผ๊ด€์„ฑ

theme.js์—์„œ theme ๊ฐ’์„ ์ง์ ‘ ๊ด€๋ฆฌํ•˜๊ณ  importํ•ด์„œ ์‚ฌ์šฉํ•˜๋Š” ๋ฐฉ์‹์€ ์ž‘์€ ํ”„๋กœ์ ํŠธ์—์„œ๋Š” ๊ดœ์ฐฎ์ง€๋งŒ ํ”„๋กœ์ ํŠธ ๊ทœ๋ชจ๊ฐ€ ์ปค์งˆ์ˆ˜๋ก ๋ณต์žกํ•ด์งˆ ์ˆ˜ ์žˆ๋‹ค. ์—ฌ๋Ÿฌ ์ปดํฌ๋„ŒํŠธ์—์„œ import๋ฅผ ๋ฐ˜๋ณตํ•˜๊ฒŒ ๋˜๊ณ , ์ด ๊ฐ’๋“ค์ด ์ค‘๋ณต๋˜๊ฑฐ๋‚˜ ๊ด€๋ฆฌ๊ฐ€ ์–ด๋ ค์›Œ์งˆ ์ˆ˜ ์žˆ๋‹ค.

ThemeProvider๋Š” ๊ทธ๋Ÿฐ ๋ฌธ์ œ๋ฅผ ๋ฐฉ์ง€ํ•˜๊ณ , ์ „์—ญ์ ์œผ๋กœ ํ…Œ๋งˆ๋ฅผ ์ผ๊ด€๋˜๊ฒŒ ๊ด€๋ฆฌํ•  ์ˆ˜ ์žˆ๋„๋ก ๋„์™€์ค€๋‹ค.

 


 

์ผ๋‹จ ์ด์œ ๋ฅผ ์ •๋ฆฌ๋Š” ํ•ด๋ดค๋Š”๋ฐ ์‚ฌ์‹ค ํฌ๊ฒŒ ์™€๋‹ฟ์ง€๊ฐ€ ์•Š์•˜๋‹ค.

๋™์  ํ…Œ๋งˆ ๋ณ€๊ฒฝ?

export const lightTheme = {
  background: "#fff",
  color: "#000",
};

export const darkTheme = {
  background: "#000",
  color: "#fff",
};

 

์ด๋ ‡๊ฒŒ theme.js์— ์ •์˜๋˜์–ด ์žˆ๋‹ค๊ณ  ๊ฐ€์ •ํ•˜๊ณ 

๋‹ค๋ฅธ ์ปดํฌ๋„ŒํŠธ์—์„œ ์‚ฌ์šฉํ•  ๋•Œ

export default function Component () {
  const [isDark,setIsDark] = useState(false);
  return(
    <h1 style={{ color : isDark ? theme.colors.dakr : theme.colors.light}}>Hello!</h1>
    <button>{isDark ?'๋‹คํฌ' :'๋ผ์ดํŠธ'}๋ชจ๋“œ ์ „ํ™˜</button>
  )
}

 

์ด๋ ‡๊ฒŒ ์‚ฌ์šฉ๋  ํ…๋ฐ ์ด๊ฒƒ๋„ ๋™์  ํ…Œ๋งˆ ๋ณ€๊ฒฝ์ด ๋˜๋Š” ๊ฑฐ ์•„๋‹Œ๊ฐ€?

๋ผ๊ณ  ์ƒ๊ฐํ–ˆ๋‹ค.

 

์•„๋ฌด๋ฆฌ ์ƒ๊ฐํ•ด๋„ ์ดํ•ด๊ฐ€ ๋˜์ง€ ์•Š์•„ chatGPT์—๊ฒŒ ์˜ˆ์‹œ๋ฅผ ๋งŒ๋“ค์–ด ๋‹ฌ๋ผ๊ณ  ์š”์ฒญํ–ˆ๋‹ค.


โœจ ThemeProvider ์˜ˆ์‹œ


export const lightTheme = {
  background: "#fff",
  color: "#000",
};

export const darkTheme = {
  background: "#000",
  color: "#fff",
};
import { createContext, useContext, useState } from "react";
import { lightTheme, darkTheme } from "./theme";

const ThemeContext = createContext();

export const ThemeProvider = ({ children }) => {
  const [isDark, setIsDark] = useState(false);
  const theme = isDark ? darkTheme : lightTheme;

  return (
    <ThemeContext.Provider value={{ theme, isDark, setIsDark }}>
      {children}
    </ThemeContext.Provider>
  );
};

export const useTheme = () => useContext(ThemeContext);
import { ThemeProvider } from "./ThemeContext";
import MyComponent from "./MyComponent";

const App = () => {
  return (
    <ThemeProvider>
      <MyComponent />
    </ThemeProvider>
  );
};

export default App;
import { useTheme } from "./ThemeContext";

const MyComponent = () => {
  const { theme, setIsDark, isDark } = useTheme();

  return (
    <div style={{ background: theme.background, color: theme.color }}>
      <button onClick={() => setIsDark((prev) => !prev)}>
        Toggle Theme
      </button>
      <p>Hello, Theme!</p>
    </div>
  );
};

export default MyComponent;

 

์ฝ”๋“œ๋ฅผ ๋ณด๋‹ˆ ๋‹จ๋ฒˆ์— ์ดํ•ด๊ฐ€ ๋˜์—ˆ๋‹ค.

 

๋ผ์ดํŠธ / ๋‹คํฌ ํ…Œ๋งˆ ๋ชจ๋“œ๋Š” ๋ชจ๋“  ํŽ˜์ด์ง€์— ์˜ํ–ฅ์„ ๋ฏธ์น˜๋Š”๋ฐ

์ผ์ผ์ด importํ•ด์„œ ์‚ฌ์šฉํ•  ๊ฒฝ์šฐ ๋ชจ๋“  ์ปดํฌ๋„ŒํŠธ ๋‚ด๋ถ€์—์„œ ํ…Œ๋งˆ ๋ชจ๋“œ์— ๋Œ€ํ•œ state๋ฅผ ๊ด€๋ฆฌํ•ด์ค˜์•ผ ํ•œ๋‹ค.

 

ํ•˜์ง€๋งŒ ThemeProvider๋ฅผ ์‚ฌ์šฉํ•˜๋ฉด Provider ํ•จ์ˆ˜ ๋‚ด๋ถ€์—์„œ state๋ฅผ ๋งŒ๋“ค์–ด ๊ด€๋ฆฌํ•˜๊ณ 

์ „์—ญ ์ƒํƒœ์—์„œ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๊ธฐ ๋•Œ๋ฌธ์— ์ฝ”๋“œ๊ฐ€ ํ›จ์”ฌ ๋” ๊ฐ„๊ฒฐํ•˜๊ณ  ์œ ์ง€๋ณด์ˆ˜๋„ ํŽธํ•˜๋‹ค.


 

์•„ํ•˜! contextAPI์ฒ˜๋Ÿผ ์ž‘๋™ํ•˜๋Š”๊ตฌ๋‚˜~

๊ทธ๋Ÿฌ๋ฉด contextAPI๋กœ ๊ตฌํ˜„ํ•ด๋„ ๋˜๋Š”๋ฐ ์™œ ThemeProvider๋ฅผ ์“ธ๊นŒ? ๐Ÿค”


โœจ  styled-components์˜ ThemeProvider vs Context API


styled-components ๊ฐ™์€ CSS-in-JS ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ์—์„œ๋Š” ์ž์ฒด์ ์ธ ThemeProvider๋ฅผ ์ œ๊ณตํ•˜๋Š”๋ฐ, ์ด๊ฒŒ Context API์™€ ๊ฑฐ์˜ ๋™์ผํ•œ ์—ญํ• ์„ ํ•œ๋‹ค. ํ•˜์ง€๋งŒ ๋‹ค์Œ๊ณผ ๊ฐ™์€ ์ฐจ์ด๊ฐ€ ์žˆ๋‹ค.

 

โœ…  styled-components์˜ ThemeProvider ์žฅ์ 

  • styled-components๋Š” ์ž๋™์œผ๋กœ theme ๊ฐ’์„ props.theme ํ˜•ํƒœ๋กœ ์ „๋‹ฌํ•ด ์ฃผ๊ธฐ ๋•Œ๋ฌธ์— ์Šคํƒ€์ผ ์ •์˜๊ฐ€ ํ›จ์”ฌ ๊น”๋”ํ•ด์ง„๋‹ค.
const Home = () => {
  return <StHome>hello</StHome>;
};

export default Home;
const StHome = styled.div`
  background-color: ${(props) => props.theme.colors.primary};
`;

 ์˜ˆ๋ฅผ ๋“ค๋ฉด ์œ„์™€ ๊ฐ™์ด ์— background-color๋ฅผ props๋กœ ์ง์ ‘ ์ „๋‹ฌํ•ด ์ฃผ์ง€ ์•Š์•„๋„ theme์— ์ ‘๊ทผํ•˜์—ฌ ์‚ฌ์šฉ์ด ๊ฐ€๋Šฅํ•˜๋‹ค.

 

  • styled-components ๋‚ด๋ถ€์ ์œผ๋กœ "์Šคํƒ€์ผ ์บ์‹ฑ"๊ณผ "์Šคํƒ€์ผ ์žฌ์‚ฌ์šฉ"์„ ์ž๋™์œผ๋กœ ๊ด€๋ฆฌํ•˜๊ธฐ ๋•Œ๋ฌธ์— ์Šคํƒ€์ผ ๋ณ€๊ฒฝ๋งŒ ๊ฐ์ง€ํ•˜๊ณ  ์ปดํฌ๋„ŒํŠธ ์ž์ฒด๋Š” ๋ฆฌ๋ Œ๋”๋ง์ด ๋˜์ง€ ์•Š์•„ ์„ฑ๋Šฅ์— ๋” ์ข‹๋‹ค.
  • css-in-js ๋ฐฉ์‹๊ณผ ์ž์—ฐ์Šค๋Ÿฝ๊ฒŒ ์–ด์šธ๋ ค์„œ ์‚ฌ์šฉ์ด ํŽธ๋ฆฌํ•จ.

โŒ  Context API๋งŒ์œผ๋กœ ์Šคํƒ€์ผ์„ ๊ด€๋ฆฌํ•  ๋•Œ์˜ ๋‹จ์ 

  • styled-components, Emotion, MUI ๋“ฑ์˜ ํ…Œ๋งˆ ์‹œ์Šคํ…œ๊ณผ ํ†ตํ•ฉํ•˜๊ธฐ ์–ด๋ ต๋‹ค → ํ•ด๋‹น ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ๋“ค์€ ๊ธฐ๋ณธ์ ์œผ๋กœ ThemeProvider๋ฅผ ์‚ฌ์šฉํ•˜๋„๋ก ์„ค๊ณ„๋˜์–ด ์žˆ์Œ.
  • ๋ฆฌ๋ Œ๋”๋ง ๋น„์šฉ์ด ์ฆ๊ฐ€ํ•  ์ˆ˜ ์žˆ๋‹ค → theme ๊ฐ’์ด ๋ฐ”๋€” ๋•Œ, Context๋ฅผ ์‚ฌ์šฉํ•˜๋Š” ๋ชจ๋“  ์ปดํฌ๋„ŒํŠธ๊ฐ€ ๋ฆฌ๋ Œ๋”๋ง ๋  ์ˆ˜ ์žˆ์Œ. (React์˜ useContext๋Š” ๊ฐ’์ด ๋ฐ”๋€Œ๋ฉด ํ•ด๋‹น Context๋ฅผ ๊ตฌ๋…ํ•˜๋Š” ๋ชจ๋“  ์ปดํฌ๋„ŒํŠธ๋ฅผ ๋‹ค์‹œ ๋ Œ๋”๋งํ•จ)
  • CSS-in-JS ๋ฐฉ์‹๋ณด๋‹ค ์ฝ”๋“œ๊ฐ€ ์ง€์ €๋ถ„ํ•ด์งˆ ์ˆ˜ ์žˆ๋‹ค → style={{ color: theme.color }} ๊ฐ™์€ ์ธ๋ผ์ธ ์Šคํƒ€์ผ์„ ๊ณ„์† ์จ์•ผ ํ•ด์„œ ์Šคํƒ€์ผ ์ฝ”๋“œ๊ฐ€ ๊ธธ์–ด์ง€๊ณ  ๊ฐ€๋…์„ฑ์ด ๋–จ์–ด์งˆ ์ˆ˜ ์žˆ์Œ.

 

์—ฌ๊ธฐ๊นŒ์ง€ ThemeProvider์— ๋Œ€ํ•ด ์•Œ์•„๋ณด์•˜๋‹ค.

์—ญ์‹œ ๋‹ค ์กด์žฌ์˜ ์ด์œ ๊ฐ€ ์žˆ๋‹ค(?)

styled-components๋Š” ์ฒ˜์Œ ์‚ฌ์šฉํ•ด ๋ณด๋Š”๋ฐ ์˜ค๋Š˜์„ ๊ธฐ์ ์œผ๋กœ ์ข€ ๋” ์นœํ•ด์กŒ์œผ๋ฉด ์ข‹๊ฒ ๋‹ค..๐Ÿ˜