부트스트랩처럼 스타일과 관련된 기능. 리액트에 내장된 기능은 아니고, 모듈을 사용한다.
예를 들어 버튼을 만든다고 하면, 디자인이 되어있는 버튼을 만들고 불러오고 싶을 때 컴포넌트 처럼 디자인을 만들어놓고 불러올 수 있는 기능이다. 즉, 스타일링된 컴포넌트를 쉽게 불러올 수 있도록 만들어진 기능이다.
기존에 리액트에서 css를 불러오는 방법은 import해서 css 파일을 불러오거나, 코드에 직접 style={{효과:"원하는 효과"}} 형식으로 적어야 했지만 이 방법은 html 파일에서 style 안에 css 코드를 직접 작성하는 것 처럼 만들 수 있다.
npm install styled-components

설치 후 package.json 파일에서 설치가 잘 되었는지 확인!
styled.element`` 를 담는다.import React from 'react'
import styled from 'styled-components'
export default function App() {
const SimpleButton = styled.button`
color: white;
background-color: black
`
const LargeButton = styled.button`
color: white;
background-color: black;
font-size: 30px
`
return (
<div>
<h2 style={{backgroundColor:"black", color:"white"}}>Styled Components</h2>
<SimpleButton>Button</SimpleButton>
<LargeButton>Large Button</LargeButton>
</div>
)
}
(결과)

그런데 simple button과 large button은 스타일은 전체적으로 똑같지만 글자의 크기만 다르다. 따라서 같은 효과인 css를 class처럼 불러오는 효과를 낼 수도 있다.
import React from 'react'
import styled from 'styled-components'
export default function App() {
const SimpleButton = styled.button`
color: white;
background-color: black
`
const LargeButton = styled(SimpleButton)`
font-size: 30px
`
return (
<div>
<h2 style={{backgroundColor:"black", color:"white"}}>Styled Components</h2>
<SimpleButton>Button</SimpleButton>
<LargeButton>Large Button</LargeButton>
</div>
)
}

결과는 같다!
그러나 첫 번째 방법과 두 번째 방법의 차이점은, 첫 번째 방법은 각자 스타일을 변경할 수 있다는 점이고, 두 번째 방법은 Simple Button 스타일을 수정하면 Large Button의 스타일도 Simple Button과 함께 스타일이 변경된다는 것이다.
import React from 'react'
import styled from 'styled-components'
export default function App() {
const SimpleButton = styled.button`
color: white;
background-color: black
`
const LargeButton = styled(SimpleButton)`
font-size: 30px
`
/*const ReactButton =()=>{
return <button>React Button</button>
}*/
const ReactButton = props =>{
//console.log(props)
return <button>{props.children}</button>
}
return (
<div>
<h2 style={{backgroundColor:"black", color:"white"}}>Styled Components</h2>
<SimpleButton>Button</SimpleButton>
<LargeButton>Large Button</LargeButton>
{/*<ReactButton />*/}
<ReactButton>React Button</ReactButton>
</div>
)
}

children은 컴포넌트의 자식요소를 말하며 하나의 컴포넌트를 다양한 요소에서 사용할 수 있다는 점에서 재사용성이 높다.
console을 확인해보면 children이 React Button이라는 값을 받고 있는 모습을 볼 수 있다.
(결과)

children이 부모 컴포넌트로부터 받은 styled component를 적용하여 React Button을 출력하고 있는 모습을 알 수 있다.
import React from 'react'
import styled from 'styled-components'
export default function App() {
const SimpleButton = styled.button`
color: white;
background-color: black
`
const LargeButton = styled(SimpleButton)`
font-size: 30px
`
/*const ReactButton =()=>{
return <button>React Button</button>
}*/
const ReactButton = props =>{
console.log(props)
return <button className={props.className}>{props.children}</button>
}
const ReactLargeButton = styled(ReactButton)`
font-size: 30px
`
return (
<div>
<h2 style={{backgroundColor:"black", color:"white"}}>Styled Components</h2>
<SimpleButton>Button</SimpleButton>
<LargeButton>Large Button</LargeButton>
{/*<ReactButton />*/}
<hr />
<ReactButton>React Button</ReactButton>
<ReactLargeButton>React Large</ReactLargeButton>
</div>
)
}
(결과)

children은 내장된 속성이다.
함수로 스타일을 생성해서 함수 안에서 조건문을 사용하여 응용한 코드
import React from 'react'
import styled from 'styled-components'
export default function App() {
const SimpleButton = styled.button`
color: white;
background-color: black
`
const LargeButton = styled(SimpleButton)`
font-size: 30px
`
/*const ReactButton =()=>{
return <button>React Button</button>
}*/
const ReactButton = props =>{
//console.log(props)
return <button className={props.className}>{props.children}</button>
}
const ReactLargeButton = styled(ReactButton)`
font-size: 30px
`
const PrimaryButton = styled.button`
/* color:orange;*/
/*color: ${
'orange'
}*/
/*color: ${function(){
return 'orange'
}}*/
color: ${ function(props){
//console.log(props)
// return 'orange'
if(props.primary){
return 'orange'
} else if(props.secondary){
return 'tomato'
} else{
return 'blue'
}
}
}
`
return (
<div>
<h2 style={{backgroundColor:"black", color:"white"}}>Styled Components</h2>
<SimpleButton>Button</SimpleButton>
<LargeButton>Large Button</LargeButton>
<hr />
{/*<ReactButton />*/}
<h2>Normal Component</h2>
<ReactButton>React Button</ReactButton>
<ReactLargeButton>React Large</ReactLargeButton>
<hr />
<h2>Dynamic Styled</h2>
<PrimaryButton>Dynamic Button</PrimaryButton>
<PrimaryButton primary="true">Dynamic Button</PrimaryButton>
<PrimaryButton secondary="true">Dynamic Button</PrimaryButton>
</div>
)
}

${()=>{}} 변수에는 보통 prop이 전달되고 primary가 true인 경우에는 orange를 반환, secondary 가 true인 경우에는 tomato를 반환
true/false가 지정되지 않은 Dynamic Button은 blue로 출력되는 모습을 볼 수 있다.
(다른 예제)
prop을 전달받아 스타일이 변화하게 만들기
//button.js
import React from 'react'
import styled from 'styled-components'
export default function Button({children,color,background}) {
const StyledButton = styled.button`
color:${props=>props.color||'white'};
background:${props=>props.background||'orange'};
border:1px solid white;
display:block;
margin-bottom: 10px
`
return (
<StyledButton color={color} background={background}>{children}</StyledButton>
)
}
//app.js
import React from 'react'
import Button from './components/Button'
export default function App() {
return (
<div>
<Button>Button</Button>
<Button color='skyblue' background='black'>Button</Button>
</div>
)
}
(결과)

Spread 연산자를 사용하기
spread 연산자를 활용해서 ...을 사용하는것도 방법이 될 수 있다
//button.js
import React from 'react'
import styled from 'styled-components'
export default function Button({children, ...props}) {
const StyledButton = styled.button`
color:${props=>props.color||'white'};
background:${props=>props.background||'orange'};
border:1px solid white;
display:block;
margin-bottom: 10px
`
return (
<StyledButton {...props}>{children}</StyledButton>
)
}
//app.js
import React from 'react'
import Button from './components/Button'
export default function App() {
return (
<div>
<Button>Button</Button>
<Button color='skyblue' background='black'>Button</Button>
</div>
)
}
결과는 위의 코드와 같다.
//app.js
import React from 'react'
import Button from './components/Button'
export default function App() {
return (
<div>
<Button>Button</Button>
<Button color='skyblue' background='black'>Button</Button>
<Button primary="true">Button</Button>
<Button primary="true">Button</Button>
</div>
)
}
//button.js
import React from 'react'
import styled, {css}from 'styled-components'
const StyledButton = styled.button`
color:${props=>props.color||'white'};
background:${props=>props.background||'orange'};
border:1px solid white;
display:block;
margin: 10px 0
${
props=>{
props.primary && css`
color: "white";
background: "navy";
border: " none
`
}
}
`
export default function Button({children, ...props}) {
return (
<StyledButton {...props}>{children}</StyledButton>
)
}

기존 css 효과는
@keyframs NAME{}
selector{
NAMAE:
animation-prop: val;
}
의 형식으로 사용하여 keyframe을 사용해서 애니메이션 효과를 넣을 수 있었다. 그런데 styled component에서 활용하는 방법은
//app.js
import React from 'react'
import Button from './components/Button'
import GlobalStyle from './components/GlobalStyle'
export default function App() {
return (
<div>
<GlobalStyle />
<Button>Defalut</Button>
<Button color='skyblue' background='black'>Color</Button>
<Button primary="true">Background</Button>
<Button primary="true">Primary</Button>
<Button animation='true' duration={5}>Animation</Button>
<Button animation='true' duration={10}>Animation</Button>
</div>
)
}
//button.js
import React from 'react'
import styled, {css, keyframes}from 'styled-components'
const StyledButton = styled.button`
color:${props=>props.color||'white'};
background:${props=>props.background||'orange'};
border:1px solid white;
display:block;
margin: 10px 0;
&:active, &:focus{
background: lightgray
} //style.button h2 <<이런식으로 사용할 수 있다
${
props=>{
props.primary && css`
color: "white";
background: "navy";
border: " none
`
}
};
${
props =>
props.animation &&
css`
/*animation: ${rotate} 2s ease-in-out infinite*/
animation: ${rotate} ${props.duration}s ease-in-out infinite
`
}
`
const rotate = keyframes`
from{
transform: rotate(0deg)
}
to{
transform: rotate(360deg)
}
`
function Button({children, ...props}) {
return (
<StyledButton {...props}>{children}</StyledButton>
)
}
export default Button
//globalstyle.js
import {createGlobalStyle} from 'styled-components'
const GlobalStyle = createGlobalStyle`
body{
margin:0;
padding:0;
}
button {
cursoe: pointer
}
`
export default GlobalStyle
(결과)

스타일을 섞어서 사용하는 개념을 mix in 이라고 한다!
import React from 'react'
import styled, {css} from 'styled-components'
import GlobalStyle from './components/GlobalStyle'
//js 내부이지만 css 사용할 수 있다. styled component의 기능
const awesomeCard = css`
box-shadow: 0 4px 6px rgba(50,50,93,0.1);
background: white;
border-radius: 10px;
padding: 20px
`
const Container = styled.div`
width: 100vw;
height: 100vh;
background:teal;
`
/*const Input = styled.input`
font-size: 30px;
color: tomato
`*/
const Input = styled.input.attrs({
maxLength: 10,
required: true
})`
font-size: 30px;
color: tomato;
${awesomeCard}
`
export default function App() {
return (
<div>
<GlobalStyle/>
<Container>
<Input
placeholder="It's time to go to bed"
/*maxLength={20}*/
/>
</Container>
</div>
)
}

ThemeProvider: theme이라는 prop이 필요하다.
import React from 'react'
import styled, {css, ThemeProvider} from 'styled-components'
import GlobalStyle from './components/GlobalStyle'
const Button = styled.button`
font-size: 1em;
margin: 1em;
padding: 0.25em 1em;
border-radius: 5px;
color: ${props=>props.theme.main};
border: 2px solid ${props=>props.theme.main}
`
Button.defaultProps={
theme:{
main: '#387ADF'
}
}
const theme = {
main: 'orange',
sub: 'teal'
}
export default function App() {
return (
<div>
<Button>Normal</Button>
<ThemeProvider theme={theme}>
<Button>Themed</Button>
</ThemeProvider>
</div>
)
}
(결과)

중첩 사용도 가능하다
import React from 'react'
import styled, {css, ThemeProvider} from 'styled-components'
import GlobalStyle from './components/GlobalStyle'
const Button = styled.button`
font-size: 1em;
margin: 1em;
padding: 0.25em 1em;
border-radius: 5px;
color: ${props=>props.theme.main};
border: 2px solid ${props=>props.theme.main}
`
Button.defaultProps={
theme:{
main: '#387ADF'
}
}
const theme = {
main: 'orange',
sub: 'teal'
}
const Article = styled.div`
width: 100px;
height: 100px;
padding: 0.25em 1em;
border-radius: 5px;
background: teal;
color: ${props=>props.theme.main};
/*${Button}{
color: dodgerblue
}*/
& Button{
color: dodgerblue
}
`
export default function App() {
return (
<div>
<Button>Normal</Button>
<ThemeProvider theme={theme}>
{/*<Article>Article</Article>
<Button>Themed</Button>*/}
<Article>Article
<Button>Nested Themed</Button>
</Article>
<Button>Themed</Button>
</ThemeProvider>
</div>
)
}
(결과)

${Button}{
color: dodgerblue
}
& Button{
color: dodgerblue
}
위의 두 문장은 같은 의미이다.