[React] Using Styled Components

task11ยท2022๋…„ 4์›” 17์ผ
0

๋ฆฌ์•กํŠธ๋ฝ€๊ฐœ๊ธฐ

๋ชฉ๋ก ๋ณด๊ธฐ
1/1
post-thumbnail

๐Ÿ’ก ์ด ํฌ์ŠคํŒ…์€ styled-components์— ๋Œ€ํ•ด ํ˜ผ์ž ๊ณต๋ถ€ํ•˜๋ฉฐ ์ •๋ฆฌํ•œ ๋‚ด์šฉ์ž…๋‹ˆ๋‹ค. ํ˜น์—ฌ๋‚˜ ์ผ๋ถ€ ์˜ฌ๋ฐ”๋ฅด์ง€ ์•Š์€ ์ •๋ณด๊ฐ€ ์žˆ์„ ์‹œ์— ์ง€์ ํ•ด์ฃผ์‹œ๋ฉด ์ •์ •ํ† ๋กํ•˜๊ฒ ์Šต๋‹ˆ๋‹ค.

๊ฐœ์š” ๐Ÿ›ซ

styled-components ์‚ฌ์šฉ๋ฒ• ์ •๋ฆฌ์™€ ํ”„๋กœ์ ํŠธ ์ฝ”๋“œ ๋ฆฌํŒฉํ† ๋ง์„ ํ†ตํ•œ ์‹ค์Šต์„ ๋ชฉํ‘œ๋กœ ํ•ฉ๋‹ˆ๋‹ค.

React์—์„œ๋Š” ๋ณดํ†ต CSS-in-JS์„ ํ†ตํ•ด ์Šคํƒ€์ผ ์ž‘์—…์„ ์ง„ํ–‰ํ•œ๋‹ค.

๋Œ€ํ‘œ์ ์œผ๋กœ ์‚ฌ์šฉ๋˜๋Š” CSS-in-JS ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ๋Š” emotion๊ณผ styled-components๊ฐ€ ์žˆ๋‹ค.

์ด๋ฒˆ ํฌ์ŠคํŒ…์—์„œ๋Š” styled-components์˜ ํŠน์ง•๊ณผ ์žฅ/๋‹จ์  ๊ทธ๋ฆฌ๊ณ  ์‚ฌ์šฉ ๋ฐฉ๋ฒ•์— ๋Œ€ํ•ด ๋‹ค๋ค„๋ณด๊ณ ์ž ํ•œ๋‹ค.


styled-components โ‡

CSS-in-JS

stlyed-components๋Š” CSS-in-JS์˜ ๋Œ€ํ‘œ์ ์ธ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ์ด๊ธฐ ๋•Œ๋ฌธ์— ์ด๋ฅผ ์•Œ๊ธฐ์ „์— CSS-in-JS์— ๋Œ€ํ•ด ์•Œ์•„์•ผํ•œ๋‹ค.

์œ„ ์ปดํฌ๋„ŒํŠธ ์Šคํƒ€์ผ ๋ฐฉ์‹์€ ๊ธฐ์กด CSS์˜ ์•„๋ž˜ ๋‹จ์ ์„ ๊ทน๋ณตํ•˜๊ณ ์ž ๊ฐœ๋ฐœ๋˜์—ˆ๋‹ค.

CSS ๋ฌธ์ œ์  (Vjeux)

  • Global namespace: ๋ชจ๋“  ์Šคํƒ€์ผ์ด global์— ์„ ์–ธ๋˜์–ด ์ค‘๋ณต๋˜์ง€ ์•Š๋Š” class ์ด๋ฆ„์„ ์ ์šฉํ•ด์•ผ ํ•˜๋Š” ๋ฌธ์ œ
  • Dependencies: css ๊ฐ„์˜ ์˜์กด๊ด€๊ณ„๋ฅผ ๊ด€๋ฆฌํ•˜๊ธฐ ํž˜๋“  ๋ฌธ์ œ
  • Dead Code Elimination: ๊ธฐ๋Šฅ ์ถ”๊ฐ€, ๋ณ€๊ฒฝ, ์‚ญ์ œ ๊ณผ์ •์—์„œ ๋ถˆํ•„์š”ํ•œ CSS๋ฅผ ์ œ๊ฑฐํ•˜๊ธฐ ์–ด๋ ค์šด ๋ฌธ์ œ
  • Minification: ํด๋ž˜์Šค ์ด๋ฆ„์˜ ์ตœ์†Œํ™” ๋ฌธ์ œ
  • Sharing Constants: JS ์ฝ”๋“œ์™€ ์ƒํƒœ ๊ฐ’์„ ๊ณต์œ ํ•  ์ˆ˜ ์—†๋Š” ๋ฌธ์ œ
  • Non-deterministic Resolution: CSS ๋กœ๋“œ ์ˆœ์„œ์— ๋”ฐ๋ผ ์Šคํƒ€์ผ ์šฐ์„  ์ˆœ์œ„๊ฐ€ ๋‹ฌ๋ผ์ง€๋Š” ๋ฌธ์ œ
  • Isolation: CSS์™€ JS๊ฐ€ ๋ถ„๋ฆฌ๋œ ํƒ“์— ์ƒ์†์— ๋”ฐ๋ฅธ ๊ฒฉ๋ฆฌ๊ฐ€ ์–ด๋ ค์šด ๋ฌธ์ œ

๊ฐ„๋‹จํ•˜๊ฒŒ ์„ค๋ช…ํ•˜์ž๋ฉด ๊ธฐ์กด CSS ์Šคํƒ€์ผ๋ง ๋ฐฉ์‹์€ ํ”„๋กœ์ ํŠธ๊ฐ€ ์ปค์งˆ์ˆ˜๋ก ๋ชจ๋“  html ์š”์†Œ์— ํด๋ž˜์Šค ๋„ค์ด๋ฐ์„ ๋ช…์‹œํ•ด์•ผํ•˜๊ณ ,

์ปดํฌ๋„ŒํŠธ ์Šคํƒ€์ผ์„ ๋ณ€๊ฒฝํ•  ๋•Œ ํด๋ž˜์Šค์— ๋งž๋Š” CSS Selector์„ ์ผ์ผํžˆ ์ฐพ์•„ ๋ณ€๊ฒฝํ•ด์•ผํ•˜๊ธฐ ๋•Œ๋ฌธ์— ๋ฒˆ๊ฑฐ๋กœ์šธ ์ˆ˜ ๋ฐ–์— ์—†๋‹ค.

๊ทธ๋ž˜์„œ ๊ธฐ์กด์— CSS ํŒŒ์ผ์„ ์ƒ์„ฑ, ๊ด€๋ฆฌํ•˜๋Š” ๊ณผ์ •์„ CSS-in-JS์˜ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ์ปดํฌ๋„ŒํŠธ ๋‹จ์œ„๋กœ ๊ฐœ๋ฐœ๋œ JSํŒŒ์ผ์— CSS ์Šคํƒ€์ผ๋ง์„ ํ•˜๊ฒŒ ๋œ๋‹ค.

ํ•˜์ง€๋งŒ, ๋ฌด์กฐ๊ฑด CSS-in-JS๊ฐ€ ์ข‹์€ ๊ฒƒ ๋งŒ์€ ์•„๋‹ˆ๋‹ค.

  • runtime overhead๊ฐ€ ์ผ์–ด๋‚  ์ˆ˜ ์žˆ๋‹ค. ์‚ฌ์šฉ์ž์™€์˜ interaction์—์„œ ์• ๋‹ˆ๋ฉ”์ด์…˜ ๋“ฑ๊ณผ ๊ฐ™์€ ์—ฐ์‚ฐ์ด ํ•„์š”ํ•œ ํŽ˜์ด์ง€์˜ ๊ฒฝ์šฐ (๋Ÿฐํƒ€์ž„์—์„œ ๋™์ ์œผ๋กœ ์Šคํƒ€์ผ์„ ์ƒ์„ฑํ•˜๊ธฐ ๋•Œ๋ฌธ์—) ์„ฑ๋Šฅ ์ด์Šˆ๊ฐ€ ๋ฐœ์ƒํ•  ์ˆ˜ ์žˆ๋‹ค.
    ์กฐ๊ธˆ ๋” ๊นŠ์ด ์ดํ•ดํ•˜๊ธฐ ์œ„ํ•ด์„œ๋Š” CSS-in-JS์˜ ๋™์ž‘๋ฐฉ์‹์ธ runtime, zero-runtime ๋“ฑ์„ ์ฐพ์•„๋ณด๊ธธ ๋ฐ”๋ž€๋‹ค.

  • ๊ธฐ์กด CSS-in-CSS ๋ฐฉ์‹์€ ์ฒซ ํŽ˜์ด์ง€๊ฐ€ ๋กœ๋“œ๋  ๋•Œ ์ ์šฉ ๊ฐ€๋Šฅํ•œ ๋ชจ๋“  ์Šคํƒ€์ผ๋“ค์„ ๋งŒ๋“ค์–ด๋‘๊ธฐ ๋•Œ๋ฌธ์— ์ปดํฌ๋„ŒํŠธ์˜ ์ƒํƒœ๊ฐ€ ๋ณ€๊ฒฝ๋œ๋‹ค ํ•˜๋”๋ผ๋„ ๋ฐ”๋กœ๋ฐ”๋กœ ์ ์šฉ์ด ๊ฐ€๋Šฅํ•˜๋‹ค.
    ํ•˜์ง€๋งŒ CSS-in-JS์˜ ๊ฒฝ์šฐ, ์ƒํƒœ๊ฐ€ ๋ณ€๊ฒฝ๋˜๋ฉด ์šฐ์„  JS์˜ CSS ์ฝ”๋“œ๋ฅผ ์ฝ์–ด์™€์„œ ํŒŒ์‹ฑํ•˜๋Š” ๋‹จ๊ณ„๋ถ€ํ„ฐ ์‹œ์ž‘ํ•˜๊ธฐ ๋•Œ๋ฌธ์— ์•„๋ฌด๋ž˜๋„ ๋Šฆ์–ด์งˆ ์ˆ˜ ๋ฐ–์— ์—†๋Š” ๋ฌธ์ œ๊ฐ€ ์žˆ๋‹ค.

  • ์ถ”๊ฐ€์ ์ธ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ ์„ค์น˜๊ฐ€ ํ•„์š”ํ•˜๊ธฐ ๋•Œ๋ฌธ์— JS์˜ ๋ฒˆ๋“ค ํฌ๊ธฐ๊ฐ€ ์ปค์ง€๋Š” ์ , ์ด์— ๋”ฐ๋ผ ์ตœ์ดˆ ๋ Œ๋”๋ง์— ์ƒ๋Œ€์ ์œผ๋กœ ์‹œ๊ฐ„์ด ๋” ์˜ค๋ž˜ ๊ฑธ๋ฆฐ๋‹ค๋Š” ๊ฒƒ ๋˜ํ•œ ๋‹จ์ ์œผ๋กœ ๋ณผ ์ˆ˜ ์žˆ๋‹ค.

์œ„ ์žฅ/๋‹จ์ ์„ ๊ณ ๋ คํ•œ๋’ค ์Šคํƒ์„ ์ฑ„์šฉํ•˜๋Š” ๊ฒƒ๋„ ์ค‘์š”ํ•˜์ง€๋งŒ
๊ฐœ์ธ์ ์œผ๋กœ ์œ ์˜๋ฏธํ•œ ํผํฌ๋จผ์Šค์˜ ์ฐจ์ด๊ฐ€ ๋‚˜์ง€ ์•Š๋Š”๋‹ค๋ฉด ๊ฐœ๋ฐœ ๋ฌธํ™”์™€ ๋งž๋Š”์ง€, ๊ฐœ๋ฐœ ์นœํ™”์ ์ธ์ง€๊ฐ€ ๊ฐ€์žฅ ์ค‘์š”ํ•œ ์ด์Šˆ๋ผ๊ณ  ์ƒ๊ฐ์ด ๋“ ๋‹ค..

Styled-components

CSS-in-JS ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ ์ค‘ styled-components๋กœ ๋””์ž์ธ ์‹œ์Šคํ…œ์„ ๊ตฌ์ถ•ํ•˜๊ธฐ๋กœ ํ–ˆ๋‹ค๊ณ  ๊ฐ€์ •ํ•˜์ž. emotion์€ ์ถ”ํ›„์— ๋‹ค๋ค„๋ณด๊ฒ ๋‹ค.

๋‚ด๊ฐ€ CSS-in-JS ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ๋“ค ์ค‘์—์„œ emotion ๋“ฑ ๋‹ค์–‘ํ•œ ๊ฒƒ๋“ค์„ ์ œ์™ธํ•˜๊ณ  styled-components๋ฅผ ๋จผ์ € ๊ณต๋ถ€ํ•˜๋Š” ์ด์œ ๋Š”

์•„์ง๊นŒ์ง„ ํƒ€ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ ๋Œ€๋น„ ์‚ฌ์šฉ๋Ÿ‰์ด ๋†’๊ธฐ ๋•Œ๋ฌธ์ด๋‹ค. (reference๊ฐ€ ๋งŽ๊ฒ ์ฃต?) ์ถ”ํ›„์—๋Š” emotion stylex stitches.js ๊ณผ ๊ฐ™์€ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ๋„ ์‚ฌ์šฉํ•ด๋ณด๊ณ ์žํ•œ๋‹ค.

stlyed-conponents์˜ ์žฅ์ ์€ ์•„๋ž˜์™€ ๊ฐ™๋‹ค. ๋Œ€๋ถ€๋ถ„ CSS-in-JS์˜ ์žฅ ๋‹จ์ ์„ ์ƒ์†๋ฐ›๊ณ  ์žˆ๋Š” ๊ฒƒ์„ ๋ณผ ์ˆ˜ ์žˆ๋‹ค.

  • CSS ๋ชจ๋ธ์„ ๋ฌธ์„œ ๋ ˆ๋ฒจ์ด ์•„๋‹Œ ์ปดํฌ๋„ŒํŠธ ๋ ˆ๋ฒจ๋กœ ์ถ”์ƒํ™”ํ•˜๋Š” ๋ชจ๋“ˆ์„ฑ
  • CSS-in-JS๋Š” JavaScript ํ™˜๊ฒฝ์„ ์ตœ๋Œ€ํ•œ ํ™œ์šฉ
  • ์ž๋ฐ”์Šคํฌ๋ฆฝํŠธ์™€ CSS ์‚ฌ์ด์˜ ์ƒ์ˆ˜์™€ ํ•จ์ˆ˜๋ฅผ ๊ณต์œ 
  • ํ˜„์žฌ ์‚ฌ์šฉ ์ค‘์ธ ์Šคํƒ€์ผ๋งŒ DOM์— ํฌํ•จ
  • ์งง์€ ๊ธธ์ด์˜ ์œ ๋‹ˆํฌ ํ•œ ํด๋ž˜์Šค๋ฅผ ์ž๋™์œผ๋กœ ์ƒ์„ฑํ•˜๋Š” ์ฝ”๋“œ ๊ฒฝ๋Ÿ‰ํ™” vendor prefix

๋‹จ์ ์€ ์•„๋ž˜์™€ ๊ฐ™๋‹ค.

  • CSS ๋Œ€๋น„ ๋†’์€ ๋Ÿฌ๋‹ ์ปค๋ธŒ(Learning Curve)
  • ์ƒˆ๋กœ์šด ์˜์กด์„ฑ ๋ฐœ์ƒ
  • ๋ณ„๋„์˜ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ ์„ค์น˜์— ๋”ฐ๋ฅธ ๋ฒˆ๋“ค ํฌ๊ธฐ ์ฆ๋Œ€ ๋ฐ CSS-in-CSS์— ๋น„ํ•ด ๋Š๋ฆฐ ์†๋„

์žฅ ๋‹จ์ ์„ ์ •๋ฆฌํ•˜๋ฉด์„œ ํ•œ๋ฒˆ ๋” ๊ฐœ๋ฐœ ์นœํ™”์ ์ธ ์ ์ด ์ค‘์š”ํ•˜๋‹ค๋Š” ์ƒ๊ฐ์ด ๋“ ๋‹ค.


How to use ๐Ÿ“–

์„ค์น˜๋ถ€ํ„ฐ ์˜ˆ์ œ๊นŒ์ง€ ์ž‘์„ฑํ•ด๋ณด์ž.

1. Install

์•„๋ž˜ ๋ช…๋ น์–ด๋ฅผ ์ž‘์„ฑํ•ด ์ƒˆ๋กœ์šด CRA ์•ฑ์„ ์ƒ์„ฑํ•˜๊ณ , styled-components๋ฅผ ์„ค์น˜ํ•ด์ค€๋‹ค.

$ npx create-react-app project-name
$ npm i styled-components

2. Basic Example

App.js ์ปดํฌ๋„ŒํŠธ์— ์•„๋ž˜์™€ ๊ฐ™์ด ์ž‘์„ฑํ•œ๋‹ค.

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

const Wrapper = styled.div`
  display: flex;
  height: 100px;
  width: 100px;
  justify-content: center;
  align-items: center;
  background-color: black;
`;


function App() {
  return <Wrapper>
    </Wrapper>;
}

export default App;

styled-components ๋ฅผ ์‚ฌ์šฉํ•˜๋ฉด ์ด๋ ‡๊ฒŒ ์Šคํƒ€์ผ์„ ์ž…๋ ฅํ•จ๊ณผ ๋™์‹œ์— ํ•ด๋‹น ์Šคํƒ€์ผ์„ ๊ฐ€์ง„ ์ปดํฌ๋„ŒํŠธ๋ฅผ ๋งŒ๋“ค ์ˆ˜ ์žˆ๋‹ค.
์œ„ ์˜ˆ์ œ์ฒ˜๋Ÿผ div ๋ฅผ ์Šคํƒ€์ผ๋ง ํ•˜๊ณ  ์‹ถ์œผ๋ฉด styled.div + ๋ฐฑํ‹ฑ์„ ์‚ฌ์šฉํ•˜๋ฉด ๋˜๊ณ , span์ด๋‚˜ button ์„ ์Šคํƒ€์ผ๋ง ํ•˜๊ณ  ์‹ถ์œผ๋ฉด styled.tag-name ์œผ๋กœ ์‚ฌ์šฉํ•˜๋ฉด ๋œ๋‹ค.

3. Theme

์ผ๊ด€์ ์ธ ์Šคํƒ€์ผ ๊ด€๋ฆฌ๋ฅผ ์œ„ํ•ด ์ž์ฃผ ์‚ฌ์šฉํ•˜๊ฒŒ ๋  ์ƒ‰์ƒ ์ฝ”๋“œ, ์‚ฌ์ด์ฆˆ ๋“ฑ์˜ ์ •๋ณด๋ฅผ ์ƒ์„ฑํ•ด ์ƒ์œ„ ์ปดํฌ๋„ŒํŠธ์— ์ •์˜ํ•  ์ˆ˜ ์žˆ๋‹ค.

styled-component์—์„œ ์ด๋Ÿฐ ๋ณ€์ˆ˜ ๊ฐ์ฒด๋ฅผ theme์ด๋ผ๊ณ  ๋ถ€๋ฅธ๋‹ค.

์ƒ์œ„ ์ปดํฌ๋„ŒํŠธ index.js

import React from 'react';
import { ThemeProvider } from 'styled-components';
import App from './App';

const darkTheme = {
  textColor: "whitesmoke",
  backgroundColor: "#111"
};

const lightTheme = {
  textColor: "#111",
  backgroundColor: "whitesmoke"
};

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

์ตœ์ƒ์œ„ ์ปจํ…Œ์ด๋„ˆ์—์„œ ThemeProvider ํƒœ๊ทธ์— theme ๊ฐ์ฒด๋ฅผ ๋ณด๋‚ด์ค€๋‹ค.

ํ•˜์œ„ ์ปดํฌ๋„ŒํŠธ App.js

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

const Title = styled.h1`
  color: ${props => props.theme.textColor};
`;

const Wrapper = styled.div`
  display: flex;
  height: 100vh;
  width: 100vw;
  justify-content: center;
  align-items: center;
  background-color: ${props => props.theme.backgroundColor};
`;


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

export default App;

theme ๊ฐ์ฒด๋Š” ํ…œํ”Œ๋ฆฟ ๋ฆฌํ„ฐ๋Ÿด ๋‚ด๋ถ€์— props.theme.value ๋กœ ๊ฐ’์— ์ ‘๊ทผํ•  ์ˆ˜ ์žˆ๋‹ค.

๋ฐ”๋กœ ํ•˜์œ„ ์ปดํฌ๋„ŒํŠธ ์™ธ์—๋„ ๋ชจ๋“  ์ปดํฌ๋„ŒํŠธ์—์„œ theme ๊ฐ์ฒด์— ์ ‘๊ทผํ•  ์ˆ˜ ์žˆ๋‹ค.


Refactor Example

CSS module๋กœ ์ž‘์„ฑ๋œ ๋ฆฌ์•กํŠธ ํ”„๋กœ์ ํŠธ๋ฅผ styled-components๋กœ ๋ฆฌํŒฉํ† ๋งํ•ด๋ณธ๋‹ค.

github link: movie-app-react-frontend


References ๐Ÿ™๐Ÿฝ

0๊ฐœ์˜ ๋Œ“๊ธ€