์ง๋ ์ฌ์ด ๋๋์๊ฒ ํผ์๋ ธ ์ฐ์ต์ค ํ์ด์ง ๋ง๋ จํด์ฃผ๊ธฐ ํ๋ก์ ํธ๋ฅผ ์ํํ๋ฉด์ ๊ฐ์ฅ ํฌ๊ฒ ๋๊ผ๋ ์ ์ ๋ฐ๋ก css์์์ ํต์ผ์ฑ์ด ์๋ค ๋ผ๋ ๊ฒ์ด์๋ค.
์ฝ 15๊ฐ์ ์ปดํฌ๋ํธ์ 12๊ฐ์ ์น์ ๊ณผ 3๊ฐ์ ํ์ด์ง๋ก ์ด๋ฃจ์ด์ง ๋ฆฌ์กํธ ์ฑ์ ๋ง๋ค๋ฉด์ ๊ฐ๊ฐ์ ์ปดํฌ๋ํธ์ ๋ง๋ style.js ํ์ผ์ ์์ฑํ๋ค.
ํ์ง๋ง ๊ทธ ๋น์์๋ CSS๋ฅผ ๊ณตํต์ผ๋ก ๊ด๋ฆฌํ ์๊ฐ๋ณด๋ค๋ ๋น ๋ฅด๊ฒ ํ๋ก์ ํธ๋ฅผ ๋๋ด๊ณ ์ถ์ ๋ง์์ด์์ด์ ๊ณตํต ์คํ์ผ์ ๊ดํ ์๊ฐ์ ์ฌ์ ๊ฐ ์์๋ค.
๊ทธ๋๋ ๋ง์ ํ์ผ ์ ๋ถ์์ด ์์๋๋ฐ, ๊ทธ ๋ถ์์ด ๊ฐ์ ธ์ฌ ๋ฌธ์ ์ ์ ๋ค์๊ณผ ๊ฐ๋ค.
- ๋งค ์ปดํฌ๋ํธ๊ฐ ์ฆ๊ฐํจ์ ๋ฐ๋ผ ์คํ์ผ ์ฝ๋์ ์ผ๊ด์ฑ์ด ๋จ์ด์ง๋ค. => ์ ์ง๋ณด์ ๋น์ฉ์ ์ฆ๊ฐ
- ์คํ์ผ ์์ฑ๊ฐ๋ค์ด ์ค๊ตฌ๋๋ฐฉ์ด๋ผ ์ด๋ค ์์ฑ์ ๊ฐ๊ณ ์๋์ง ์ฝ๋๋ก ํ์ธ์ด ์ด๋ ต๋ค => ํ์ ์์์ ๋ฌธ์
- ์คํ์ผ๋ง๋ค ๋ค๋ฅธ ์์ฑ์ ๊ฐ๊ณ ์์ด์ ์ฌ์ฌ์ฉ์ด ๋ถ๊ฐ๋ฅํ๋ค => ๋นํจ์จ์ฑ ์ฆ๊ฐ
์ด๋ฐ ๋ฌธ์ ์ ์ styled-components
๋ฅผ ์ฌ์ฉํ๋ค๋ฉด context API๋ฅผ ํตํด ํ ๋ฒ์ ํด๊ฒฐํ ์ ์๋๋ฐ, ๊ทธ ๋ฐฉ๋ฒ์ด ๋ฐ๋ก ThemeProvider
์ด๋ค.
ThemeProvider
styled-components๋ ThemeProvider
๋ฅผ ํตํด์ ๊ฐ๋ ฅํ theming ์ ๋ต์ ์ ๊ณตํ๋ค.
์์์ ๋ด๊ฐ ๋ฌธ์ ์ ์ ํด๊ฒฐํ๊ธฐ ์ํด์๋ context api๋ฅผ ์ฌ์ฉํ๋ค๊ณ ํ๋๋ฐ, ์ด ThemeProvider
๊ฐ ๋ฐ๋ก context ๋ฅผ ์ฌ์ฉํด์ ๋ชจ๋ ๋ฆฌ์กํธ ์ปดํฌ๋ํธ์๊ฒ theme ์์ฑ์ ์ ๋ฌํ๋ ์ญํ ์ ์ํํ๋ค.
์ด๋ค ์ปดํฌ๋ํธ๊ฐ ๋ช ๋จ๊ณ๋ฅผ ๊ฑฐ์ณ์ depth๋ฅผ ๊ฐ๋๋ผ๋ ๋ฃจํธ์ ThemeProvider
๊ฐ ์๋ฆฌ์ก๊ณ ์๋ค๋ฉด ๋ชจ๋ ๋ ๋ ํธ๋ฆฌ์ ์์์๋ ๋ค theme ์์ฑ์ ๊ฐ๊ฒ๋๋ค.
์๋ฅผ ๋ค์ด์
import React from "react";
import { ThemeProvider } from "styled-components";
const theme = {
// ... ์ฌ์ฉ์ ์ ์ theme code
}
const Home = () => {
return (
<ThemeProvider theme={theme}>
<Header />
<Sidebar />
<HeroSection />
<Footer />
</ThemeProvider>
);
}
๊ณผ ๊ฐ์ ๋ฐฉ์์ผ๋ก ์ฌ์ฉํ๋๋ฐ, ์ด ๊ฒฝ์ฐ Home ์ปดํฌ๋ํธ์์ ์ต์๋จ์ ํ๊ทธ๊ฐ <ThemeProvider>
์ด๋ฏ๋ก ํ์ ์์์ ๋ชจ๋ ์ปดํฌ๋ํธ๋ <ThemeProvider>
์ props๋ก ๋์ด๊ฐ๋ theme
๊ฐ์ ์ฌ์ฉํ ์ ์๊ฒ๋๋ ๊ฒ์ด๋ค.
์ด์ ๊ธฐ๋ณธ ์ปจ์ ์ ๋ํด์ ์์๋ณด์.
๊ธฐ๋ณธ ์ปจ์ ์ดํดํ๊ธฐ
Context API
๋ฅผ ์ด์ฉํ๋ค๋ ThemeProvider์ ๊ธฐ๋ณธ ์ปจ์
์ ์ดํดํ๊ธฐ ์ํด์ ๊ฐ๋จํ 2๊ฐ์ ๋ฒํผ์ ๋ง๋ค์ด ๋ณด์.
import React from "react";
import styled from "styled-components";
const Button = styled.button`
font-size: 1em;
margin: 1em;
padding: 0.25em 1em;
border-radius: 3px;
`;
const ThemeProviderPrac = () => {
return (
<div>
<Button>Normal 1</Button>
<Button>Normal 2</Button>
</div>
);
};
๊ทธ๋ผ ์๋ฌด ์คํ์ผ์ด ์ ์ฉ๋์ง ์์ ๋ฒํผ์ด ์์ฑ๋๋ค.
<ThemeProvider>
๋ฅผ ์ฌ์ฉํ๋ ค๋ฉด ์ผ๋ฐ์ ์ธ Context API๋ฅผ ์ฌ์ฉํ๋ ๊ณผ์ ๊ณผ ๋์ผํ๋ค.
๋ชจ๋ ์์ ์ปดํฌ๋ํธ๋ฅผ ๊ฐ์ธ๋ Context ์ญํ ์ ์ํํ๊ธฐ ์ํด <ThemeProvider>
๋ฅผ Theme์ ์คํ์ผ ์์ฑ์ ์ ์ฉ๋ฐ์ผ๋ ค๋ ์ปดํฌ๋ํธ ๋ ๋ ํธ๋ฆฌ ์ต์๋จ์ ๋ฐฐ์นํ๋ค.
... ์๋ต
const ThemeProviderPrac = () => {
return (
<div>
<Button>Normal</Button>
<ThemeProvider theme={theme}>
<Button>Themed</Button>
</ThemeProvider>
</div>
);
};
... ์๋ต
๊ทธ๋ฆฌ๊ณ ์์ ๋น๊ต๋ฅผ ์ํด ๊ธฐ์กด์ ๋ง๋ค์๋ Button
์ปดํฌ๋ํธ์ defaultProps๋ ์ง์ ํด๋ณด์.
Button.defaultProps = {
theme: {
main: "palevioletred",
}
}
์์ ๊ณผ์ ์ ๊ฑฐ์น๋ฉด ๊ฒฐ๋ก ์ ์ผ๋ก ๋ค์๊ณผ ๊ฐ์ ์ฝ๋๊ฐ ์์ฑ๋๋ค.
import React from "react";
import styled, { ThemeProvider } from "styled-components";
const Button = styled.button`
font-size: 1em;
margin: 1em;
padding: 0.25em 1em;
border-radius: 3px;
color: ${(props) => props.theme.main};
border: 2px solid ${(props) => props.theme.main};
`;
Button.defaultProps = {
theme: {
main: "palevioletred",
},
};
const theme = {
main: "mediumseagreen",
};
const ThemeProviderPrac = () => {
return (
<div>
<Button>Normal</Button>
<ThemeProvider theme={theme}>
<Button>Themed</Button>
</ThemeProvider>
</div>
);
};
export default ThemeProviderPrac;
๊ทธ๋ฆฌ๊ณ ์ํํ๋ค๋ฉด ThemeProvider๋ฅผ ์ฌ์ฉํ ์ปดํฌ๋ํธ๋ฅผ ๋ง๋ค ์ ์๊ฒ ๋๋ค.
๋ ๋์๊ฐ์ Function Themes๋ฅผ ์ฌ์ฉํด๋ณด๊ธฐ
๋ ๋์๊ฐ์ theme props๋ฅผ ๊ฐ์ฒด์ธ์ ํจ์๋ก ๋๊ธธ ์๋ ์๋ค.
ํจ์๋ก theem props๋ฅผ ๋๊ธด๋ค๋ฉด ๋ฌธ๋งฅ์ ์ผ๋ก ํ ๋ง๊ฐ ๋ง๋ค์ด์ง ์ ์์ด์ ๋ ๋ค์ํ ์คํ์ผ๋ง์ด ๊ฐ๋ฅํ๋ค.
๊ฐ๋ณ๊ฒ ์ปจ์ ๋ง ๋๊ปด๋ณด์.
ํจ์๋ฅผ ์ด์ฉํ <ThemeProvider>
๋ฅผ ์ด์ฉํ๊ธฐ ์ํด์ 2๊ฐ์ ๋ฒํผ์ ๋ง๋ค๊ณ ๊ฐ๊ฐ์ Theme์ props๋ก foreground์ fg ์์ฑ๊ณผ background์ bg ์์ฑ ๊ฐ์ palevioletred
์ white
๋ก ์ค๋ณด์.
import React from "react";
import styled, { ThemeProvider } from "styled-components";
const Button = styled.button`
color: ${(props) => props.theme.fg};
background: ${(props) => props.theme.bg};
border: 2px solid ${(props) => props.theme.fg};
font-size: 1em;
margin: 1em;
padding: 0.25em 1em;
border-radius: 3px;
`;
const theme = {
fg: "palevioletred",
bg: "white",
};
const ThemeProviderPrac = () => {
return (
<div>
<ThemeProvider theme={theme}>
<Button>๊ธฐ๋ณธ theme props ์ฌ์ฉ</Button>
<Button>ํจ์๋ฅผ ์ด์ฉํ new theme</Button>
</ThemeProvider>
</div>
);
};
export default ThemeProviderPrac;
๊ทธ๋ผ ๋ค์๊ณผ ๊ฐ์ ๋์ผํ palevioletred ์์ ๊ฐ์ง ๋ฒํผ 2๊ฐ๊ฐ ๋์จ๋ค.
์ด์ invertTheme
์ด๋ผ๋ ํจ์๋ฅผ ๋ง๋ค์ด๋ณด์.
const invertTheme = ({ fg, bg }) => ({
fg: bg,
bg: fg
});
์ด ํจ์๋ ๋ณด์ด๋ค์ถ์ด ์๋ก ์์ ์ค์์นญ ํ์ฌ theme props๋ฅผ ๋ฐํํ๊ฒ ๋๋ค.
ํด๋น ํจ์์ theme props๋ฅผ ์๋ก์ด ThemeProvider
์ปจํ
์คํธ๋ฅผ ๋ง๋ค์ด์ ๊ฐ์ธ๋ณด์.
import React from "react";
import styled, { ThemeProvider } from "styled-components";
const Button = styled.button`
color: ${(props) => props.theme.fg};
background: ${(props) => props.theme.bg};
border: 2px solid ${(props) => props.theme.fg};
font-size: 1em;
margin: 1em;
padding: 0.25em 1em;
border-radius: 3px;
`;
const theme = {
fg: "palevioletred",
bg: "white",
};
const invertTheme = ({ fg, bg }) => ({
fg: bg,
bg: fg,
});
const ThemeProviderPrac = () => {
return (
<div>
<ThemeProvider theme={theme}>
<Button>๊ธฐ๋ณธ theme props ์ฌ์ฉ</Button>
<Button>ํจ์๋ฅผ ์ด์ฉํ new theme</Button>
</ThemeProvider>
</div>
);
};
export default ThemeProviderPrac;
์ฐ๋ฆฌ๋ ์ด์ ํจ์๋ฅผ ์ด์ฉํด์ theme์ ๋ฐ๊ฟ ์ ์๊ฒ ๋์๋ค
ํ๋ก์ ํธ์์ ์ด๋ป๊ฒ ์ฌ์ฉํ ๊น?
๊ทธ๋ ๋ค๋ฉด ์ค์ ํ๋ก์ ํธ์์๋ ์ด๋ป๊ฒ ์ฌ์ฉํ ๊น?
์ด๋ ต๊ฒ ์๊ฐํ์ง ๋ง์.
- ๊ทธ๋ฅ ์ฐ๋ฆฌ๊ฐ context api๋ฅผ ์ฌ์ฉํ๋ ๊ฒ๊ณผ ๋น์ทํ ๋๋์ผ๋ก ์ฌ์ฉํ๋ฉด ๋๋ค.
- ๊ณตํต๋๋ ๊ฐ๋ค์
<ThemeProvider>
์์ ๋ฐํํด์ฃผ๊ณ ์ค๋ณต๋ ์ฝ๋ ์ค์ธ๋ค๋ ๋๋์ผ๋ก ์ฐ์.
์ด๋ ๊ฒ๋ง ์ด์ผ๊ธฐ ํ๋ฉด ์ดํด๊ฐ ํ๋ค ์ ์์ผ๋ ์ค์ ์ฝ๋๋ฅผ ๋ด๋ณด์.
์๋ฅผ ๋ค์ด display:flex๋ h1์ font-size, color๋ฅผ ThemeProvider๋ฅผ ์ฌ์ฉํด์ ๊ณตํต ์์ ์ ํ๋ค๊ณ ํด๋ณด์.
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;
์์ ํ์ผ์ ๋์จ ๋ด์ฉ์ ๋ค์๊ณผ ๊ฐ๋ค.
- font-size ํต์ผ
- color ํต์ผ
- display flex center ์๋ ์์ฑ๊ธฐ
๊ทธ๋ฆฌ๊ณ App.js
ํ์ผ์์ ์ฐ๋ฆฌ๊ฐ ๋ง๋ theme๋ค์ ์ฌ์ฉํด๋ณด์.
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;
styled-components์์ props๋ก ๋์ค๋ ๊ฐ์ฒด ํน์ ๊ฐ๋ค์ ์ฌ์ฉํ๋ ค๋ฉด ${}
๋ฆฌํฐ๋ด๋ก ์ธํจํน ํด์ฃผ๋ฉด ๋๋ค!
์์ ์ฝ๋๋ ์ข ์๊ฐ์ ๊ฐ๊ณ ์ฒ์ฒํ ํ์ดํ ํด๋ณด๊ธธ ์ถ์ฒํ๋ค.
๊ทธ๋ผ ๋ค์ ๊ฐ์ ํ๋ฉด์ด ๊ณตํต ์์ฑ์ด ์ ์ฉ๋์ด ์ ์ถ๋ ฅ๋๋ค.
๋๊ธ