[React]Styled-Components 사용법

승환입니다·2022년 10월 19일
13
post-thumbnail
post-custom-banner

안녕하세요 ! 오늘은 CSS 라이브러리중에 하나인 Styled-Components를 알아보겠습니다 ! ╰(°▽°)╯ 와아아


-시작하기 앞서-

CSS 라이브러리는 Styled-Components 이외에도 Sass,PostCss그리고 tailWind,부트스트랩 등 정말 많이 있는데여!
뭐가 좋고 나쁘다고 할거없이 장단점이 있고 개인적인 코딩스타일에 따라 맞는 라이브러리를 쓰시면 될거같습니다!
개인적으로 저는 Styled-components가 좋아서 포스팅중입니다 ╰(°▽°)╯

Styled-Components란?

Styled-Compoenents는 css를 편하게 코딩할수있게 도와주는 라이브러리입니다!
클래스 충돌방지이외에도 유지보수에 도움되는 여러가지 기능을 가지고있어서 개발자들이 좋아해여


Styled-Components의 장단점

스타일드컴포넌트는 CSS in JS입니다.
즉,CSS코드를 자바스크립트안에서 작성해야합니다.
맨날 확장자에 index.css ,, 이러면서 파일만드는게 귀찮잖아여
한 js파일안에서 깔끔하게 css까지 작성할 수 있는 장점도 있고
코드 상속 , props , nesting 등 다양한 기능을 가지고 있습니다!
하지만 그렇게되면 브라우저가 렌더링을 할떄 js코드를 쭉 다운받는데 js안에서 쓴 css코드+ 스타일드컴포넌트 문법자체도 재컴파일해야해서 렌더링시간이 조금 더 오래걸리겠죠?

장점

  • 스타일드 컴포넌트의 다양한 기능으로 유지보수가 좋아지고 코드양을 줄일 수 있다.
  • 한 파일안에서 css까지 작성해서 폴더구조가 깔끔하다.

단점

  • 한 파일안에 css코드와 js코드가 다 있기떄문에 가독성이 떨어질수도 있다.
  • 렌더링할떄 재컴파일문제로 렌더링시간이 길어져 성능에 좋지않다.(미미합니다)

Styled-Components 환경설정하기

이제 본격적으로 styled-components를 써보겠습니다.╰(°▽°)╯
우선 styled-components는 CRA가 기본적으로 가지고있지않아서 따로 설치를 해야합니다!

npm install --save styled-components

npm i --save-dev @types/styled-components //타입스크립트시면 이것도 설치해주세요!

그리고 자동완성을 원하시면 익스텐션 vscode-styled-components까지 설치해주세요!


기본적인 문법 알아보기

  • 기본 골격
  • 상속
  • css
  • nesting
  • attrs
  • as
  • Animation

기본 골격

import React from "react";
import "./App.css";
import styled from "styled-components";

const Hello = styled.div`
  width: 100px;  //css를 여기다가 작성합니다!
  height: 100px;
  background-color: red;
`;

function App() {
  return <Hello className="App"></Hello>;
}

export default App;

결과

여기서 주의사항!

  1. Hello 같이 컴포넌트가 될 이름의 첫글자는 무조건 대문자여야합니다!
  2. styledimport 하세요!

기본 골격
const [컴포넌트이름] = styled.[태그]

내가 만약 컴포넌트이름은 Box 태그는 div로된걸 만들고 있다면?

const Box= styled.div`
  //css 입력하는 곳
`

이런식으로 쓰시면됩니다!
a태그를 만들고 있다면

const Box= styled.a`
  //css 입력하는 곳
`

컴포넌트이름을 내마음대로 정할수있어서 html골격을 봤을떄 좀 더 가독성이 생길꺼같아여

상속

상속은 어떤걸 열심히 스타일링했는데 그걸 그대로 가져와서 뭔가를 추가해주고싶을떄 많이써요!

즉 , 공통적으로 스타일링할게 있을떄 많이씁니다!

import React from "react";
import "./App.css";
import styled from "styled-components";

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

const CircleBox = styled(Box)`
  border-radius: 50%;
  background-color: blue;
`;
function App() {
  return (
    <div className="App">
      <Box></Box>
      <CircleBox></CircleBox>
    </div>
  );
}

export default App;

결과

상속하는법
const [컴포넌트이름] = styled(상속받을 태그이름)``

css & props

props

import React from "react";
import "./App.css";
import styled from "styled-components";

const Button = styled.button<{ border: string }>`
  width: 100px;
  height: 50px;
  border: 3px solid ${(props) => props.border || "green"};
`;

function App() {
  return (
    <div className="App">
      <Button border={""}>클릭</Button>
      <Button border={"red"}>클릭</Button>
      <Button border={"blue"}>클릭</Button>
      <Button border={"black"}>클릭</Button>
    </div>
  );
}

export default App;

결과

스타일드 컴포넌트의 장점중 하나는 유연하게 이미만든 컴포넌트들을 바꿀 수 있다는것이예영
props로 값을 전달하고
동적으로 css 스타일링을 할 수 있답니다!
border을 넣지않았다면 테두리를 녹색으로 만들었어요!

${props=>props.전달한변수이름}

CSS

props는 한줄의 코드를 조건부로 사용할 수 있다면
여러줄의 코드를 조건부로 할려면 어떻게해야할까여?

styled-component에 내장되어있는 css를 import해옵니다!

import React from "react";
import "./App.css";
import styled, { css } from "styled-components";
const Button = styled.button<{ border: string; huge?: boolean }>`
  width: 100px;            //styled.button< {프롭스명 : 타입지정}

  height: 50px;
  border: 3px solid ${(props) => props.border || "green"};

  ${(props) =>
    props.huge && //만약 huge가 있다면 실행해줘
    css`
      width: 8rem;
      height: 10rem;
      font-size: 2em;
    `}
`;

function App() {
  return (
    <div className="App">
      <Button border={""}>클릭</Button>
      <Button border={"red"}>클릭</Button>
      <Button border={"blue"}>클릭</Button>
      <Button border={"black"}>클릭</Button>
      <Button border={"pink"} huge>
        클릭!!
      </Button>
    </div>
  );
}

export default App;

결과

pink버튼만 커졌죠?
완전 유용합니다 ! ╰(°▽°)╯

nesting

태그 컴포넌트를 만들떄마다 계속 const 컴포넌트이름 styled 하기 번거롭잖아여 그렇기때문에
주요태그만 컴포넌트화시키고 나머지는 nesting문법으로 태그를 접근합니다!

예시를 한번 보겠습니다!

import React from "react";
import "./App.css";
import styled from "styled-components";

const Box = styled.div`
  width: 300px;
  height: 100px;

  & > div { //Box 컴포넌트 바로 아래 div에 접근
    font-size: 32px;
    color: pink;
  }

  & > p { //Box 컴포넌트 바로 아래 p에 접근
    font-size: 16px;
    color: green;
  }
`;

function App() {
  return (
    <div className="App">
      <Box>
        <div>안녕하세요!</div>
        <p>오늘 저녁 뭐먹을까요? 배고픈데,,</p>
      </Box>
    </div>
  );
}

export default App;

결과

이렇게 하위태그를 & 문법으로 접근할 수 있답니다.
그러면 중심이되는 태그만 컴포넌트화시키고 나머지는 nesting문법으로 접근하면 좀 더 좋겠죠?!

attrs

input 같은경우 attribute 정말 많잖아여?
그거 하나씩 쓰기 힘들떄 스타일드 컴포넌트에 추가해주면 정말 편하게 할 수 있어요!
attrs를 써서 한번 간단하게 예시코드를 짜볼게요!

import React from "react";
import "./App.css";
import styled from "styled-components";

const InputCheckbox = styled.input.attrs({
  type: "checkbox",
  checked: true,
})`
  width: 100px;
  height: 100px;
`;

const InputBox = styled.input.attrs({
  required: true,
  placeholder: "여기에 글을 써주세요!",
})`
  height: 50px;
  padding: 5px;
  border: 1px solid black;
  margin: 5px;
`;
function App() {
  return (
    <div className="App">
      <InputCheckbox></InputCheckbox>
      <InputBox></InputBox>
      <InputBox></InputBox>
      <InputBox></InputBox>
    </div>
  );
}

export default App;

결과

attrs에 미리 적어두면 html쪽에 정말 깔끔해지는거같아여!
유지보수면에서도 정말 좋아서 잘쓰면 좋을꺼같네여 !! ╰(°▽°)╯

const 컴포넌트이름=styled.input.attrs({내가 쓰고 싶은 속성값})

as

어떤걸 div태그로 만들었는데
딱 한곳에서 css는 똑같지만 링크 태그로 바꾸고싶다면 어떻게할까여?

그땐 as 문법을 쓰면됩니다!

import React from "react";
import "./App.css";
import styled from "styled-components";

const Box = styled.div`
  width: 300px;
  height: 100px;

  & > div {
    font-size: 32px;
    color: pink;
  }

  & > p {
    font-size: 16px;
    color: green;
  }
`;

function App() {
  return (
    <div className="App">
      <Box>
        <div>안녕하세요!</div>
        <p>오늘 저녁 뭐먹을까요? 배고픈데,,</p>
      </Box>
      <Box as="a" href="#"> //여기가 바꼇어여!
        링크로 바꼇당
      </Box>
    </div>
  );
}

export default App;

결과

Animation

마지막으로 Animation입니다!
스타일드 컴포넌트에서 Animation으로 쓰는방법은 Pure css랑은 조금 다른데여
한번 적용을 해보겠습니다! ^____^

import React from "react";
import "./App.css";
import styled, { keyframes } from "styled-components";

const MovingBox = keyframes` 
  0%{//Keyframes에 animation css를 적어줍니다!
    transform: translateX(-300px);
  }
  50%{
    background-color: blue;
    border-radius: 50%;
    transform: translateX(300px);
  }
  100%{
    background-color: red;
    transform: translateX(-300px);
  }
`;

const Box = styled.div`
  margin: 0 auto;
  width: 100px;
  height: 100px;
  background-color: red;
  animation: ${MovingBox} 3s infinite;
`;//그 애니메이션 컴포넌트를 이곳에 적어주고
 //그후엔 Pure CSS와 똑같습니다!!

const Main = styled.div``;
function App() {
  return (
    <Main className="App">
      <Box></Box>
    </Main>
  );
}

export default App;

결과

간단하게 스타일드컴포넌트로 animation을 구현해보았습니다!

그 외 문법 알아보기

  • GlobalStyle
  • ThemeProvider

GlobalStyle

globalStyle은 협업 , 개인 프로젝트시작 전에 공통으로 적용해야할 코드를 쓰고 싶을떄 씁니다!

css를 한번 초기화 시켜겠습니다!

//GlobalStyle.tsx
import { createGlobalStyle } from "styled-components";
const GlobalStyle = createGlobalStyle`
html, body, div, span, applet, object, iframe,
h1, h2, h3, h4, h5, h6, p, blockquote, pre,
a, abbr, acronym, address, big, cite, code,
del, dfn, em, img, ins, kbd, q, s, samp,
small, strike, strong, sub, sup, tt, var,
b, u, i, center,
dl, dt, dd, ol, ul, li,
fieldset, form, label, legend,
table, caption, tbody, tfoot, thead, tr, th, td,
article, aside, canvas, details, embed, 
figure, figcaption, footer, header, hgroup, 
menu, nav, output, ruby, section, summary,
time, mark, audio, video {
	margin: 0;
	padding: 0;
	border: 0;
	font-size: 100%;
	font: inherit;
	vertical-align: baseline;
}
/* HTML5 display-role reset for older browsers */
article, aside, details, figcaption, figure, 
footer, header, hgroup, menu, nav, section {
	display: block;
}
body {
	line-height: 1;
}
ol, ul {
	list-style: none;
}
blockquote, q {
	quotes: none;
}
blockquote:before, blockquote:after,
q:before, q:after {
	content: '';
	content: none;
}
table {
	border-collapse: collapse;
	border-spacing: 0;
}
`;

export default GlobalStyle;

  1. src폴더아래에 GlobalStyle.tsx파일을 만듭니다.
  2. createGlobalStyle을 import 해옵니다
  3. GlobalStyle을 index.tsx에 적용합니다

적용 후

ThemeProvider

저희 다크모드 많이 쓰잖아여 !
아마 context api를 사용해서 바꿔줬을꺼예여
하지만 스타일드컴포넌트를 쓴다면 context api를 쓰지 않고도 정말 간단하게 다크모드를 구현할 수있습니다!

천천히 기본설정을 해볼게여 ╰(°▽°)╯

설정 순서

  • styled.d.ts 파일만들기 //이곳에서 DefaultTheme의 타입을 지정해요
  • theme.ts 파일 만들기 // 이곳에서 theme을 설정해여
  • index.tsx에 themeProvider를 추가해줘요!

이제 하나씩 해볼게여!

//styled.d.ts
import "styled-components";

declare module "styled-components" {
  export interface DefaultTheme {
    textColor: string;
    bgColor: string;
  } // DefaultTheme에서 여러분이 
  //쓸 변수를 지정해주셔야해여
  //저는 텍스트와 배경만 지정하겠습니다!
}

타입스크립트에서 제공하지않은 타입을 저희가 수동으로 추가해주고싶으면 styled.d.ts파일에서 추가를 해주면돼요!
저는 DefaultTheme를 추가하겠씁니다!

//theme.ts
import { DefaultTheme } from "styled-components";

export const darkTheme: DefaultTheme = {
  bgColor: "#2f3640",
  textColor: "#f5f6fa",
};

export const lightTheme: DefaultTheme = {
  bgColor: "#f5f6fa",
  textColor: "#2f3640",
};//아까 추가한 DefaultTheme 타입을 가져왔습니다!
//다크모드 구현을 위해 darkTheme, lightTheme을 만들어줬습니다!

마지막으로 ThemeProvider을 index.tsx에 추가해줄게요!

import React from "react";
import ReactDOM from "react-dom/client";
import "./index.css";
import App from "./App";
import reportWebVitals from "./reportWebVitals";
import GlobalStyle from "./GlobalStyle";
import { ThemeProvider } from "styled-components";
import { darkTheme, lightTheme } from "./theme";

const root = ReactDOM.createRoot(
  document.getElementById("root") as HTMLElement
);
root.render(
  <React.StrictMode>
    <ThemeProvider theme={darkTheme}>
      <GlobalStyle />
      <App />
    </ThemeProvider>
  </React.StrictMode>
);

theme={제가 지정한 theme}

만약 어떤 버튼을 눌렀을떄 다크모드에서 라이트모드로 바꾸고싶다면?
theme안에 darkTheme을 lightTheme으로 바꾸면 되겠죠?! ╰(°▽°)╯


환경설정은 다 끝냈으니 적용을 해볼게요!

import React from "react";
import "./App.css";
import styled from "styled-components";

const Box = styled.div``;

const Main = styled.div`
  background-color: ${(props) => props.theme.bgColor};
  color: ${(props) => props.theme.textColor};
  height: 100vh;
`;
function App() {
  return (
    <Main className="App">
      <Box>
        <div>안녕하세요!</div>
        <p>오늘 저녁 뭐먹을까요? 배고픈데,,</p>
      </Box>
      <Box as="a" href="#">
        링크로 바꼇당
      </Box>
      <p>안녕</p>
    </Main>
  );
}

export default App;

결과

lightTheme으로 바꾼다면?

결과

이렇게 간단하게 다크모드를 구현할 수 있답니다!

마치며

오늘 css 라이브러리중에 스타일드 컴포넌트를 알아보았습니다!
한번배워두면 정말 좋은 라이브러리니까 배워두면 좋을꺼같아여!!

요즘 트랜드가 큰 규모의 프로젝트에서는 Sass+PostCSS vs styled-component구도인데 50대50 같아여
자기 스타일에 맞는 라이브러리 한개만 쭉 쓰는것도 좋지만 협업할때 다른 개발자분들이랑 합을 맞추려면 두개다 쓸줄아는게 좋을꺼같아요!

profile
자바스크립트를 좋아합니다.
post-custom-banner

0개의 댓글