본문 바로가기

웹공부/React

React에서 styled components 사용하기

https://styled-components.com/

 

styled-components

CSS for the <Component> Age

styled-components.com

styled components는 css 페이지를 따로 만들지 않고, javascript 안에서 편하게 스타일을 적용할 수 있게 해준다.

css가 적용된 컴포넌트를 사용자 정의 이름으로 생성해 코드의 가독성을 높여준다.

 

  • styled-component 설치 명령어(in terminal)
npm i styled-components

 

 

  • styled-component 사용법

styled-component를 설치했으면, 사용할 페이지에 import 해줘야 한다.

import styled from "styled-components";

 

 

1. 스타일 적용된 태그 생성하기

 

스타일이 적용된 사용자 정의 태그를 생성하는 방법은 아래와 같다.

const {사용자 정의 이름} = styled.{html 태그명}`{css 코드}`;

 

여기서 주의할 점은, html 태그명 뒤에 css코드를 쓸 때 backtick(`, ~표시 있는 타자기)기호를 사용해야 한다.

!!!작은따옴표('), 큰따옴표("") 아님!!!

 

사용 예시는 아래와 같다.

import React from "react";
import styled from "styled-components";

const Father=styled.div`
  display:flex;
`;

const Box=styled.div`
  background-color:teal;
  width:100px;
  height:100px;
`



function App() {
  return 
  <Father>
    <Box />
  </Father>;
}

export default App;

 

가로, 세로 높이가 100인 teal 색의 box를 생성하는코드이다.

 

 

 

 

2. 컴포넌트에 props 전달하기

 

그런데, Box를 여러개 만들되, 다른 속성은 모두 동일하게 유지하되 색깔만 바꾸고 싶다면 어떻게 해야할까?

const Box1, Box2, Box3...를 생성해 background-color 부분만 코드를 변경한다면 중복되는 코드가 많아 굉장히 비효율적인 코드가 될 것이다.

 

사용자 정의 컴포넌트에 background-color에 대한 속성만 props로 전달할 수 있으면 이런 코드의 비효율을 극복해내고, 하나의 Box 컴포넌트를 이용해 색깔만 다른 Box 여러개를 생성할수 있을 것이다!

컴포넌트에 props를 전달하는 방법에 대해 알아보자.

 

 <Box bgColor="teal">

이런식으로 컴포넌트에 {전달하고자하는 props 이름}="{전달할 내용}"을 써주면, props가 전달된다!

 

const Box=styled.div`
  background-color:${(props)=>props.bgColor};
  width:100px;
  height:100px;
`

우리가 지정한 컴포넌트에서 props값을 받아와 background-color에 적용하기 위해서는 전달받을 변수명 부분을

${(props)=>props.{전달한 props명}}으로 바꿔주면, 사용자가 전달한 props가 background-color에 적용된다.

 

 

 

 

 

3. 컴포넌트 확장하기

 

어떤 사람은 기존 컴포넌트 Box가 가진 속성들을 그대로 가져와 사용하되, 거기에 추가적으로 속성 몇가지를 더 추가하여 사용하고 싶을 수도 있다. 그럼 Box에 있는 css 코드들을 복붙한 다음, 추가할 코드를 적어 새로운 컴포넌트를 생성해야 할까? 그것보다 더 간단하게 컴포넌트를 확장할 수 있는 방법이 있다.

 

아래와 같은 규칙으로 컴포넌트를 확장할 수 있다.

const Circle=styled({확장할 컴포넌트명})`
  {추가할 css 코드}
`

 

예를 들어 Box 컴포넌트에 적용된 css 속성을 그대로 가져오되, border-radius 속성을 추가해 도형의 모양을 원으로 변경하고자 한다고 생각해보자. 위 코드 규칙을 적용하면, 손쉽게 Box 컴포넌트의 확장버전인 Circle 컴포넌트를 생성할 수 있다!

import React from "react";
import styled from "styled-components";

const Father=styled.div`
  display:flex;
`;

const Box=styled.div`
  background-color:${(props)=>props.bgColor};
  width:100px;
  height:100px;
`
const Circle=styled(Box)`
  border-radius:50px;
`

function App() {
  return 
  <Father>
    <Box bgColor="teal"/> 
    <Circle bgColor="tomato" />
  </Father>;
}

 

 

 

 

 

4. 컴포넌트 렌더링 시 태그 변경하기(컴포넌트 확장하지 않고, 모든 것을 동일하게 적용)

 

이번에는 특정 컴포넌트가 가진 속성을 그대로 가지고 오되, 렌더링시 표시되는 html 태그 이름만을 변경하고 싶을때 사용할 수 있는 기능을 알아보자.

예를들어, Box 컴포넌트가 현재는 div 태그이지만, 이것을 button 태그로 바꾸고 싶다면? const Box 태그를 그대로 복붙한 다음, html 태그 부분만 div->button으로 바꿔야 할까?

아니다! const Box 컴포넌트를 그대로 사용하되, 아래와 같이 as="" 부분을 추가하면, 렌더링시 전달한 html 태그명으로 해당 컴포넌트가 렌더링된다.

<Box as="{html 태그명}">

 

 

 

 

 

5. keyframes 이용해 animation 적용하기

 

styled-components를 이용해서 컴포넌트에 동적인 애니메이션 효과 또한 줄 수 있다.

애니메이션 효과를 줄 땐, "styled-components" 안에 포함되어있는 keyframes를 이용하기 때문에, 이를 import 해줘야 사용 가능하다.

import styled, {keyframes} from "styled-components";

 

keyframes를 사용해 아래와 같은 애니메이션 효과를 적용해보자.

 

 

위와 같은 애니메이션 효과를 적용하려면 1) 회전 효과 2)도형 테두리 변경 효과가 필요하다.

적용할 애니메이션 효과 이름을 rotationAnimation으로 하여 해당 에니메이션 효과를 정의해보자.

const {사용자 정의명}=keyframes`{적용할 애니메이션 코드}`

 

애니메이션 효과의 경우, 위 같은 포맷으로 코드를 작성한다.

 

const rotationAnimation=keyframes`
0% {
  transform:rotate(0deg);
  border-radius:0px;
}
50%{
  transform:rotate(180deg);
  border-radius:100px;
}
100%{
  transform:rotate(360deg);
  border-radius:0px;
}
`;

 

0~100%까지를 애니메이션 적용의 1cycle이라고 생각하면 된다.

애니메이션이 1cycle이 적용될 때, 0px에서 시작된 테두리둥글기가 50px(원)을 찍고 다시 0px(사각형)으로 돌아와야 한다.

그리고 애니메이션 1cycle당 도형을 360도 회전시키고 싶으므로 transform:rotate(0deg) -> (180deg) -> (360deg)를 적용해 1바퀴 회전 효과를 줄 수 있다. 

 

해당 animation 코드를 Box 컴포넌트에 적용하고 싶으면, Box 컴포넌트의 컴포넌트 속성에

animation: ${rotationAnimation}을 추가해주면 끝!

 

+) 10s linear infinite 로 애니메이션 적용 속도와 시간을 정의해준다.

-> {애니메이션 1cycle이 진행되는데 걸리는 속도} / {linear: 일정한 속도로 적용} / infinite(시간제한X, 무한히 적용)

const Box=styled.div`
  display:flex;
  justify-content:center;
  align-items:center;
  background-color:tomato;
  width:200px;
  height:200px;
  animation:${rotationAnimation} 10s linear infinite;

 

 

 

6. 특정 컴포넌트에 속해있는 자식 요소에만 선택적으로 스타일 적용하기

 

이제 "하트 뿅뿅 이모지"를 Box 안에 추가해보자.

거기에 추가로, 아래 움짤처럼 이모지에 마우스를 올리면, 이모지 크기가 커지는 애니메이션 효과(hover) + 이모지를 마우스로 누르고 있으면 이모지가 사라지는 효과(active)도 추가적으로 구현해볼 것이다.

 

 

 

우선, Emoji 컴포넌트를 하나 생성해 Box 컴포넌트 안에 넣어주었다. 그럼 박스 안에 이모지가 들어간 모양으로 도형이 빙글빙글 돌아가는 것을 확인할 수 있다.

import styled, {keyframes} from "styled-components";

const Wrapper=styled.div`
  min-height:1000px;
  display:flex;
  justify-content:center;
  align-items:center;
`;

const Emoji=styled.span`
  font-size:40px;
`;

const rotationAnimation=keyframes`
0% {
  transform:rotate(0deg);
  border-radius:0px;
}
50%{
  transform:rotate(180deg);
  border-radius:100px;
}
100%{
  transform:rotate(360deg);
  border-radius:0px;
}
`;

const Box=styled.div`
  display:flex;
  justify-content:center;
  align-items:center;
  background-color:tomato;
  width:200px;
  height:200px;
  animation:${rotationAnimation} 10s linear infinite;
`;

function App() {
  return <Wrapper>
    <Box><Emoji as="p">😍</Emoji></Box>
    <Btn>button</Btn>
  </Wrapper>
   
}

export default App;

 

우리는 Emoji 컴포넌트에 마우스를 올리면 폰트크기가 40px -> 80px로 증가하는 효과를 주고싶은데,

Box 안에 있는 Emoji 컴포넌트에만 해당 효과를 주고 싶다. 그런데 Box 안과 밖 둘 다 Emoji 컴포넌트가 사용되고있다면 어떻게 해야할까? const Emoji 안에 해당 효과를 적용하면 모든 이모지에 효과가 적용될 테니 말이다.

 

특정 컴포넌트 안에 위치한 자식요소에만 스타일을 적용하고 싶다면, 부모 컴포넌트 생성 코드 안에 자식 컴포넌트 이름을 넣고, 적용할 css 효과를 작성해주면 된다. 작성 포맷은 아래와 같다.

 

&:hover{}는 {자식 컴포넌트명}:hover와 같다.

단, 가독성을 더 좋게 하기 위해서 자식컴포넌트 안에서 & 기호를 사용해 써 준 것이라고 생각하면 된다.

const {부모 컴포넌트}=styled.div`
  ${자식 컴포넌트} {
    &:hover{
      font-size:80px;
    }
 }
`;

 

 

 

즉, Box 컴포넌트 안에 있는 Emoji에만 hover, active 효과를 적용하려면 아래와 같이 코드를 작성하면 된다.

Box 컴포넌트 밖에 위치한 Emoji 컴포넌트에는 해당 css 효과가 적용되지 않는다.

import Rreact from 'react';
import styled, {keyframes} from "styled-components";

const Wrapper=styled.div`
  min-height:1000px;
  display:flex;
  justify-content:center;
  align-items:center;
`;

const Emoji=styled.span`
  font-size:40px;
`;

const rotationAnimation=keyframes`
0% {
  transform:rotate(0deg);
  border-radius:0px;
}
50%{
  transform:rotate(180deg);
  border-radius:100px;
}
100%{
  transform:rotate(360deg);
  border-radius:0px;
}
`;

const Box=styled.div`
  display:flex;
  justify-content:center;
  align-items:center;
  background-color:tomato;
  width:200px;
  height:200px;
  animation:${rotationAnimation} 10s linear infinite;
  ${Emoji} {
    &:hover{
      font-size:80px;
    }
    &:active{
      opacity:0;
    }
  }
 
`;

const ani=keyframes`
  from{
    color:tomato;
  }to{
    color:teal;
  }
`

function App() {
  return <Wrapper>
    <Box><Emoji as="p">😍</Emoji></Box>
  </Wrapper>
   
}

export default App;

 

 

 

 

 

 

7. ThemeProvider 적용하기 (간단한 darkMode, lightMode 적용 실습)

 

styled-component에는 색상 적용시 테마를 바꾸면, 웹페이지 색깔 테마가 한번에 바뀌도록 할 수 있는 좋은 기능이 존재한다. ThemeProvider라는 건데, 이를 사용하기 위해서는 사용할 페이지에 import 해줘야한다.

import {ThemeProvider} from 'styled-components';

 

 

index.js

1) 페이지 렌더링 시 뿌리가 되는 index.js 페이지에서, ThemeProvider 기능을 적용할 컴포넌트를 <ThemeProvider />로 감싸주면 해당 컴포넌트에서 테마 적용 기능을 사용할 수 있다. 우리는 App.js페이지에서 테마 기능을 적용할 것이므로, 아래와 같이 <App /> 컴포넌트를 감싸준다.

2) 적용할 테마에 대한 css 효과를 index.js 페이지에 작성한다.
그리고 작성한 테마 스타일을 props 전달로 넘겨주면 App.js에서 해당 테마에 접근할 수 있다.

★단, 테마(lightMode, darkMode)안에 있는 변수명들은 모두 같아야한다. 그래야 테마이름을 lightMode, darkMode로만 바꿔줬을 때 스타일 변경 적용이 호환될 수 있기 때문!!

import React from 'react';
import ReactDOM from 'react-dom/client';
import './index.css';
import App from './App';
import reportWebVitals from './reportWebVitals';
import styled, {ThemeProvider} from 'styled-components';

const lightMode={
  backgroundColor:"whitesmoke",
  color:"black"
}

const darkMode={
  backgroundColor:"black",
  color:"whitesmoke"
}

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

// If you want to start measuring performance in your app, pass a function
// to log results (for example: reportWebVitals(console.log))
// or send to an analytics endpoint. Learn more: https://bit.ly/CRA-vitals
reportWebVitals();
App.js

App.js에서 index.js에서 정의한 테마를 가져올 때는 컴포넌트에 props 전달받기와 동일한 방식으로 테마를 가져오면 된다.

작성 포맷은 아래와 같다.

 {css 속성명}:${(props)=>props.theme.{테마에 있는 변수명}};
import './App.css';
import styled, {keyframes} from "styled-components";

const Title=styled.h1`
  font-size:50px;
  color:${(props)=>props.theme.color};
`
const Wrapper=styled.div`
  background-color:${(props)=>props.theme.backgroundColor};
  display:flex;
  width:100vw;
  height:100vh;
  justify-content:center;
  align-items:center;
`

function App() {
  return <Wrapper>
    <Title>Hello</Title>
  </Wrapper>
   
}

export default App;

 

 

index.js 파일에서 ThemeProvider 컴포넌트의 props를 lightMode->darkMode로만 변경하면 아래와 같이 테마색이 반전되는 것을 구현할 수 있다!

'웹공부 > React' 카테고리의 다른 글

React에서 Recoil로 상태관리하기  (0) 2024.03.11
React에서 typescript 사용하기  (0) 2024.01.16
React 공부 9일차  (0) 2023.08.22
React 공부 8일차  (0) 2023.08.21
React 공부 7일차  (0) 2023.08.18