React (7)

eg_kim·2024년 8월 27일

React

목록 보기
7/10
post-thumbnail

리액트에 대해 알아보자 (7)

Styled Components

부트스트랩처럼 스타일과 관련된 기능. 리액트에 내장된 기능은 아니고, 모듈을 사용한다.

예를 들어 버튼을 만든다고 하면, 디자인이 되어있는 버튼을 만들고 불러오고 싶을 때 컴포넌트 처럼 디자인을 만들어놓고 불러올 수 있는 기능이다. 즉, 스타일링된 컴포넌트를 쉽게 불러올 수 있도록 만들어진 기능이다.

기존에 리액트에서 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}

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


(결과)

children이 부모 컴포넌트로부터 받은 styled component를 적용하여 React Button을 출력하고 있는 모습을 알 수 있다.


함수로 생성된 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
  `

  /*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>
  )
}

결과는 위의 코드와 같다.

응용하기 2

//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>
  )
}

응용하기 3 (애니메이션 효과)

기존 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 효과

스타일을 섞어서 사용하는 개념을 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
 }

위의 두 문장은 같은 의미이다.

profile
오늘의 공부 기록📝

0개의 댓글