์ค์ ํ๋ก์ ํธ์์๋ ์ฌ์ฉ์์๊ฒ ๋คํฌ ๋ชจ๋์ ๋ผ์ดํธ ๋ชจ๋๋ฅผ ์ ๊ณตํ๋ ๊ฒ์ด ์ค์ํ 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๋ก ๊ตฌํํ ํ
๋ง ์์คํ
์ ํ์ฅ์ฑ๋ ์ข๊ณ , ์ ์ง๋ณด์๋ ์ฝ๋ค.
๋คํฌ๋ชจ๋ ๋ฒํผ์ ๋ฃ๊ณ ์ถ๋ค๋ฉด ์ด ๊ตฌ์กฐ๋ฅผ ๊ธฐ๋ฐ์ผ๋ก ์์ํด๋ณด์!
'๐ค Web > ๐ React' ์นดํ ๊ณ ๋ฆฌ์ ๋ค๋ฅธ ๊ธ
Styled Components - ์ ๋๋ฉ์ด์ , ์ปดํฌ๋ํธ ์ ํ์, ์ค์ฒฉ ์คํ์ผ๋ง (0) | 2025.03.26 |
---|---|
Styled Component์์ ์ปดํฌ๋ํธ ํ์ฅํ๊ธฐ (0) | 2025.03.26 |
๋ฆฌ์กํธ ํด๋๊ตฌ์กฐ์ ์ ์์ด ์์๊น (0) | 2023.02.17 |
๊ฐ๋ฐ์๋๊ตฌ ์ผ๋ฌด์ฅ๊ฒ ์ฐ๊ธฐ (0) | 2023.02.17 |
๋ฐ์ํ ์น์์์ ์ปจํ ์ด๋ ํฌ๊ธฐ (0) | 2023.02.17 |
๋๊ธ