[TIL] Day47 #CDD #Styled Components #Storybook #useRef

Beanxxยท2022๋…„ 6์›” 30์ผ
0

TIL

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

2022.06.30(Thurs)

[TIL] Day47
[SEB FE] Day46

โ˜‘๏ธย Component Driven Development (CDD)

โžฐย ๋ถ€ํ’ˆ ๋‹จ์œ„๋กœ UI ์ปดํฌ๋„ŒํŠธ๋ฅผ ๋งŒ๋“ค์–ด ๋‚˜๊ฐ€๋Š” ๊ฐœ๋ฐœ ์ง„ํ–‰
โžฐย ์žฌ์‚ฌ์šฉ ๊ฐ€๋Šฅํ•œ ์ปดํฌ๋„ŒํŠธ ๊ฐœ๋ฐœ ๊ฐ€๋Šฅ
โžฐย ์ปดํฌ๋„ŒํŠธ ๋‹จ์œ„๋กœ ๋งŒ๋“ค์–ด ํŽ˜์ด์ง€๋ฅผ ์กฐ๋ฆฝํ•˜๋Š” ๊ฐœ๋ฐœ ๋ฐฉ์‹ โ‡’ ์ƒํ–ฅ์‹ ๊ฐœ๋ฐœ

๐Ÿ™Œย CSS โ†’ SASS โ†’ BEM โ†’ CSS Modules โ†’ Styled Components

โžฐย ๊ตฌ์กฐํ™”๋œ CSS ํ•„์š”์„ฑ์ด ๋Œ€๋‘๋œ ๋ฐฐ๊ฒฝ

  1. ์ ์  ์ปค์ง€๋Š” ํ”„๋กœ์ ํŠธ ๊ทœ๋ชจ & ๋ณต์žก๋„ (ํŒ€์› ์ˆ˜ ์ฆ๊ฐ€ โฌ†๏ธ)
  2. ๐Ÿ“ฑ๋ชจ๋ฐ”์ผ/ํƒœ๋ธ”๋ฆฟ ๋“ฑ์„ ๋น„๋กฏํ•œ ๋‹ค์–‘ํ•œ ๋””๋ฐ”์ด์Šค ๋“ฑ์žฅ์œผ๋กœ ๋” ๋ณต์žกํ•ด์ง„ CSS

๐Ÿ“Žย CSS ์ „์ฒ˜๋ฆฌ๊ธฐ(Preprocessor)

: CSS๊ฐ€ ๊ตฌ์กฐ์ ์œผ๋กœ ์ž‘์„ฑ๋  ์ˆ˜ ์žˆ๊ฒŒ ๋„์›€์„ ์ฃผ๋Š” ๋„๊ตฌ

โœ‹ย ๊ฐ CSS ์ „์ฒ˜๋ฆฌ๊ธฐ์— ๋งž๋Š” Compiler๋ฅผ ์‚ฌ์šฉํ•ด์•ผ ํ•จ โ†’ ์ปดํŒŒ์ผ ํ›„, CSS ๋ฌธ์„œ๋กœ ๋ณ€ํ™˜

โžฐย SASS

Syntactically Awesome Style Sheets
๐Ÿ”นย CSS๋ฅผ ํ™•์žฅํ•ด ์ฃผ๋Š” Scripting ์–ธ์–ด
๐Ÿ”นย ํŠน์ • ์†์„ฑ ๊ฐ’์„ ๋ณ€์ˆ˜๋กœ ์„ ์–ธ โ†’ ํ•„์š”ํ•œ ๊ณณ์— ์„ ์–ธ๋œ ๋ณ€์ˆ˜ ์ ์šฉ
โ‡’ ๋ฐ˜๋ณต๋˜๋Š” ์ฝ”๋“œ๋ฅผ ์„ ์–ธ 1๋ฒˆ์œผ๋กœ ์—ฌ๋Ÿฌ ๊ณณ์—์„œ ์žฌ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๋„๋ก ํ•ด ์ฃผ๋Š” ๊ธฐ๋Šฅ ์กด์žฌ

๐Ÿ™Œย Read SCSS Code โ†’ ์ „์ฒ˜๋ฆฌ โ†’ ์ปดํŒŒ์ผ โ†’ ์ „์—ญ CSS ๋ฒˆ๋“ค ํŒŒ์ผ์„ ์ƒ์„ฑํ•ด์ฃผ๋Š” ์ „์ฒ˜๋ฆฌ๊ธฐ ์—ญํ• 

โœ‹ย ์Šคํƒ€์ผ ๊ฒน์น˜๋Š” ๋ฌธ์ œ ํ•ด๊ฒฐ์„ ์œ„ํ•ด ๊ณ„์ธต ๊ตฌ์กฐ๋ฅผ ๋งŒ๋“ค์–ด CSS ์šฉ๋Ÿ‰ ์–ด๋งˆ์–ด๋งˆํ•˜๊ฒŒ ์ปค์ง€๊ฒŒ ๋จ โฌ†๏ธ

๐Ÿ“Žย CSS ๋ฐฉ๋ฒ•๋ก 

โžฐย ์ง€ํ–ฅ์  (BEM, OOCSS, SMACSS)

  • ์ฝ”๋“œ์˜ ์žฌ์‚ฌ์šฉ
  • ์ฝ”๋“œ์˜ ๊ฐ„๊ฒฐํ™” (์œ ์ง€ ๋ณด์ˆ˜ ์šฉ์ด)
  • ์ฝ”๋“œ์˜ ํ™•์žฅ์„ฑ
  • ์ฝ”๋“œ์˜ ์˜ˆ์ธก์„ฑ (ํด๋ž˜์Šค๋ช…์œผ๋กœ ์˜๋ฏธ ์˜ˆ์ธก)

โžฐย BEM

: Block, Element, Modifier๋กœ ๊ตฌ๋ถ„ํ•˜์—ฌ ํด๋ž˜์Šค๋ช…์„ ์ž‘์„ฑํ•˜๋Š” ๋ฐฉ๋ฒ• (โ€”-, __ ์œผ๋กœ ๊ตฌ๋ถ„)

.header__navigationโ€”-navi-text {
	color: red;
}

{/* Block: header */}
{/* Element: navigation */}
{/* Modifier: navi-text */}
  • Block: ์ „์ฒด๋ฅผ ๊ฐ์‹ธ๊ณ  ์žˆ๋Š” ๋ธ”๋Ÿญ ์š”์†Œ
  • Element: ๋ธ”๋Ÿญ์ด ํฌํ•จํ•˜๊ณ  ์žˆ๋Š” ํ•œ ์กฐ๊ฐ
  • Modifier: ๋ธ”๋Ÿญ ๋˜๋Š” ์š”์†Œ์˜ ์†์„ฑ

๐Ÿ‘Žย ํด๋ž˜์Šค๋ช… ์„ ํƒ์ž ์žฅํ™ฉ โ†’ ๋ถˆํ•„์š”ํ•œ ๋งˆํฌ์—… โฌ†๏ธย โ†’ ์žฌ์‚ฌ์šฉํ•  ๋•Œ๋งˆ๋‹ค ๋ชจ๋“  UI ์ปดํฌ๋„ŒํŠธ ๋ช…์‹œ์  ํ™•์žฅ ํ•„์š”

๐Ÿ‘Žย ๋กœ์ง ์ƒ ์ง„์ •ํ•œ ์บก์Šํ™” โŒย โ†’ ๊ฐœ๋ฐœ์ž๋“ค์€ ์œ ์ผํ•œ ํด๋ž˜์Šค๋ช… ์„ ํƒ์— ์˜์กดํ•  ์ˆ˜ ๋ฐ–์—โ€ฆ

โŒ˜ ์บก์Šํ™”(encapsulation; ๊ฐ์ฒด ์†์„ฑ&ํ–‰์œ„๋ฅผ ํ•˜๋‚˜๋กœ ๋ฌถ๊ณ  ์‹ค์ œ ๊ตฌํ˜„ ๋‚ด์šฉ ์ผ๋ถ€๋ฅผ ์™ธ๋ถ€์— ๊ฐ์ถฐ ์€๋‹‰ํ•˜๋Š” ๊ฐœ๋…)

๐Ÿ“Žย CSS-in-JS

CSS๋ฅผ ์ปดํฌ๋„ŒํŠธ ์˜์—ญ์œผ๋กœ ๋ถˆ๋Ÿฌ๋“ค์ด๊ธฐ ์œ„ํ•ด ํƒ„์ƒ

ex. Styled-Component

ํŠน์ง•๐Ÿ‘๐Ÿ‘Ž
CSS๊ธฐ๋ณธ์  ์Šคํƒ€์ผ๋ง ๋ฐฉ๋ฒ•-- ์ผ๊ด€๋œ ํŒจํ„ด ๊ฐ–๊ธฐ ์–ด๋ ค์›€
- !important ๋‚จ์šฉ
SASSํ”„๋กœ๊ทธ๋ž˜๋ฐ ๋ฐฉ๋ฒ•๋ก  ๋„์ž… โ†’ ์ปดํŒŒ์ผ๋œ CSS ์ƒ์„ฑ ์ „์ฒ˜๋ฆฌ๊ธฐ- ๋ณ€์ˆ˜/ํ•จ์ˆ˜/์ƒ์† ๊ฐœ๋… ํ™œ์šฉ โ†’ ์žฌ์‚ฌ์šฉ
- CSS ๊ตฌ์กฐํ™”
- ์ „์ฒ˜๋ฆฌ ๊ณผ์ • ํ•„์š”
- ๋””๋ฒ„๊น… ์–ด๋ ค์›€
- ์ปดํŒŒ์ผํ•œ CSS ํŒŒ์ผ ๊ฑฐ๋Œ€ํ•ด์ง
BEMCSS ํด๋ž˜์Šค๋ช… ์ž‘์„ฑ์— ์ผ๊ด€๋œ ํŒจํ„ด์„ ๊ฐ•์ œํ•˜๋Š” ๋ฐฉ๋ฒ•๋ก - ๋„ค์ด๋ฐ์œผ๋กœ ๋ฌธ์ œ ํ•ด๊ฒฐ
- ์ „์ฒ˜๋ฆฌ ๊ณผ์ • ๋ถˆํ•„์š” โœ•
- ์„ ํƒ์ž ์ด๋ฆ„ ์žฅํ™ฉ
- ํด๋ž˜์Šค ๋ชฉ๋ก ๋งŽ์•„์ง
Styled-Component์ปดํฌ๋„ŒํŠธ ๊ธฐ๋ฐ˜์œผ๋กœ CSS๋ฅผ ์ž‘์„ฑํ•  ์ˆ˜ ์žˆ๊ฒŒ ๋„์™€์ฃผ๋Š” ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ- CSS๋ฅผ ์ปดํฌ๋„ŒํŠธ ์•ˆ์œผ๋กœ ์บก์Šํ™”
- ๋„ค์ด๋ฐ/์ตœ์ ํ™” ์‹ ๊ฒฝ ์“ธ ํ•„์š” โœ•
- ๋น ๋ฅธ ํŽ˜์ด์ง€ ๋กœ๋“œ ๋ถˆ๋ฆฌ


โ˜‘๏ธย CDD ๊ฐœ๋ฐœ ๋„๊ตฌ

๐Ÿ“Žย Styled Components

โžฐย ๊ธฐ๋Šฅ์  / ์ƒํƒœ๋ฅผ ๊ฐ€์ง„ ์ปดํฌ๋„ŒํŠธ๋“ค๋กœ๋ถ€ํ„ฐ UI๋ฅผ ์™„์ „ํžˆ ๋ถ„๋ฆฌํ•˜์—ฌ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๋Š” ๋‹จ์ˆœํ•œ ํŒจํ„ด
โžฐย HTML + JS + CSS๊นŒ์ง€ ๋ฌถ์–ด์„œ ํ•˜๋‚˜์˜ JSํŒŒ์ผ ์•ˆ์—์„œ ์ปดํฌ๋„ŒํŠธ ๋‹จ์œ„๋กœ ๊ฐœ๋ฐœํ•  ์ˆ˜ ์žˆ์Œ

# install
# with npm
$ npm install --save styled-components

# with yarn
$ yarn add styled-components
{/* package.json์— ์ฝ”๋“œ ์ถ”๊ฐ€ ๊ถŒ์žฅ -> ์—ฌ๋Ÿฌ ๋ฒ„์ „ Styled Components ์„ค์น˜๋จ */}
{
  "resolutions": {
    "styled-components": "^5"
  }
}
// Styled Components๋ฅผ ์‚ฌ์šฉํ•  ํŒŒ์ผ๋กœ ๋ถˆ๋Ÿฌ์˜ค๊ธฐ
import styled from 'styled-components'

โžฐย ์ปดํฌ๋„ŒํŠธ ์ƒ์„ฑ

  • ์ปดํฌ๋„ŒํŠธ ์„ ์–ธ โ†’ styled.ํƒœ๊ทธ์ข…๋ฅ˜ ํ• ๋‹น โ†’ ๋ฐฑํ‹ฑ ์•ˆ์— ๊ธฐ์กด CSS ๋ฌธ๋ฒ•๊ณผ ๋˜‘๊ฐ™์ด ์Šคํƒ€์ผ ์†์„ฑ ์ž‘์„ฑ
  • ES6์˜ Template Literals ๋ฌธ๋ฒ•์„ ์‚ฌ์šฉํ•˜์—ฌ ๋ฐฑํ‹ฑ(`) ์‚ฌ์šฉ
const ์ปดํฌ๋„ŒํŠธ์ด๋ฆ„ = styled.ํƒœ๊ทธ์ข…๋ฅ˜`
  CSS์†์„ฑ1: ์†์„ฑ๊ฐ’;
  CSS์†์„ฑ2: ์†์„ฑ๊ฐ’;
`;

const BlueButton = styled.button`
  background-color: blue;
  color: white;

	// hover ์†์„ฑ์€ &:hover์œผ๋กœ ์ฒ˜๋ฆฌ
	&:hover { 
    background: cornflowerblue;
    color: white;
    transition: 0.5s;
  }
`;

โžฐย ์ปดํฌ๋„ŒํŠธ ์žฌํ™œ์šฉ โ†’ new ์ปดํฌ๋„ŒํŠธ ์ƒ์„ฑ

const ์ปดํฌ๋„ŒํŠธ์ด๋ฆ„ = styled(์žฌํ™œ์šฉํ•  ์ปดํฌ๋„ŒํŠธ)`
  ์ถ”๊ฐ€ํ•  CSS์†์„ฑ1: ์†์„ฑ๊ฐ’;
  ์ถ”๊ฐ€ํ•  CSS์†์„ฑ2: ์†์„ฑ๊ฐ’;
`;

const BigBlueButton = styled(BlueButton)`
  padding: 10px;
  margin-top: 10px;
`

โžฐย Props ํ™œ์šฉ

const ์ปดํฌ๋„ŒํŠธ์ด๋ฆ„ = styled.ํƒœ๊ทธ์ข…๋ฅ˜`
	CSS์†์„ฑ: ${(props) => ํ•จ์ˆ˜์ฝ”๋“œ}
`;

// 1) Props๋กœ ์กฐ๊ฑด๋ถ€ ๋ Œ๋”๋ง
const Button1 = styled.button`
  background: ${(props) => (props.skyblue ? "skyblue" : "white")};
`;

// 2) Props ๊ฐ’์œผ๋กœ ๋ Œ๋”๋ง
const Button2 = styled.button`
  background: ${(props) => (props.color ? props.color : "white")};
`;

const Button3 = styled.button`
  background: ${(props) => props.color || "white"};
`;

โžฐย ์ „์—ญ ์Šคํƒ€์ผ ์„ค์ •

import { createGlobalStyle } from "styled-components";

const GlobalStyle = createGlobalStyle`
  button {
    padding: 5px;
    margin: 2px;
    border-radius: 5px;
  }
`;

export default GlobalStyle;
import "./App.css";
import styled from "styled-components";
import GlobalStyle from "./GlobalStyle";

// ... ์œ„์—์„œ ์„ ์–ธ ๋Œ€์ฒด

function App() {
  return (
    <>
      <BlueButton>Blue Button</BlueButton>
      <br />
      <BigBlueButton>Big Blue Button</BigBlueButton>
      
			{/* ์ „์—ญ ์Šคํƒ€์ผ์ธ <GlobalStyle/> ์ปดํฌ๋„ŒํŠธ๋ฅผ ์ตœ์ƒ์œ„ ์ปดํฌ๋„ŒํŠธ์—์„œ ์‚ฌ์šฉ */}
			<GlobalStyle />
      <Button1>Button1</Button1>
      <Button1 skyblue>Button1</Button1>
      <br />
      <Button2>Button2</Button2>
      <Button2 color="orange">Button2</Button2>
      <Button2 color="tomato">Button2</Button2>
      <br />
      <Button3>Button3</Button3>
      <Button3 color="pink">Button3</Button3>
      <Button3 color="turquoise">Button3</Button3>
    </>
  );
}

export default App;

๐Ÿ“Žย Storybook

CDD๋ฅผ ์ง€์›ํ•˜๋Š” ๋„๊ตฌ ์ค‘ ํ•˜๋‚˜๋กœ Component Explorer(์ปดํฌ๋„ŒํŠธ ํƒ์ƒ‰๊ธฐ) ๋“ฑ์žฅ
์ปดํฌ๋„ŒํŠธ ํƒ์ƒ‰๊ธฐ์—” ๋งŽ์€ UI ๊ฐœ๋ฐœ ๋„๊ตฌ๊ฐ€ ์žˆ๋Š”๋ฐ ๊ทธ ์ค‘ ํ•˜๋‚˜๊ฐ€ Storybook
โ‡’ UI ๊ฐœ๋ฐœ ์ฆ‰, CDD๋ฅผ ํ•˜๊ธฐ ์œ„ํ•œ ๋„๊ตฌ

  • ๊ฐ๊ฐ์˜ ์ปดํฌ๋„ŒํŠธ๋“ค์„ ๋”ฐ๋กœ ๊ตฌ์„ฑ โ†’ ํ•œ๋ฒˆ์— ํ•˜๋‚˜์˜ ์ปดํฌ๋„ŒํŠธ์—์„œ ์ž‘์—… ๊ฐ€๋Šฅ
  • ์žฌ์‚ฌ์šฉ์„ฑ ํ™•๋Œ€๋ฅผ ์œ„ํ•ด ์ปดํฌ๋„ŒํŠธ๋ฅผ ๋ฌธ์„œํ™”ํ•˜๊ณ ,
    ์ž๋™์œผ๋กœ ์ปดํฌ๋„ŒํŠธ๋ฅผ ์‹œ๊ฐํ™”ํ•˜์—ฌ ์‹œ๋ฎฌ๋ ˆ์ด์…˜ํ•  ์ˆ˜ ์žˆ๋Š” ๋‹ค์–‘ํ•œ ํ…Œ์ŠคํŠธ ์ƒํƒœ ํ™•์ธ ๊ฐ€๋Šฅ

๐Ÿ‘ย  ๋ฒ„๊ทธ ์‚ฌ์ „ ๋ฐฉ์ง€
๐Ÿ‘ย ํ…Œ์ŠคํŠธ ๋ฐ ๊ฐœ๋ฐœ ์†๋„ ํ–ฅ์ƒ
๐Ÿ‘ย ์˜์กด์„ฑ ๊ฑฑ์ •ํ•˜์ง€ ์•Š๊ณ  ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜ ๋นŒ๋“œ ๊ฐ€๋Šฅ

โžฐย Whyย UI๊ฐœ๋ฐœ๋„๊ตฌ(Storybook) ์‚ฌ์šฉ?

: Storybook์€ ๊ธฐ๋ณธ์ ์œผ๋กœ ๋…๋ฆฝ์ ์ธ ๊ฐœ๋ฐœ ํ™˜๊ฒฝ์—์„œ ์‹คํ–‰
โ‡’ ๊ฐœ๋ฐœ์ž๋Š” ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜์˜ ๋‹ค์–‘ํ•œ ์ƒํ™ฉ์— ๊ตฌ์• ๋ฐ›์ง€ ์•Š๊ณ  UI ์ปดํฌ๋„ŒํŠธ๋ฅผ ์ง‘์ค‘์ ์œผ๋กœ ๊ฐœ๋ฐœ ๊ฐ€๋Šฅ

โœ‹ย ์ด๋ฒคํŠธ๋ฅผ ํ†ตํ•ด ์ƒํƒœ๋ฅผ ๋ณ€๊ฒฝํ•˜๋Š” ๊ณผ์ •์„ ๊ฑฐ์น˜์ง€ ์•Š์•„๋„ ์ƒํƒœ ๋ณ€ํ™”์— ๋”ฐ๋ฅธ ์ปดํฌ๋„ŒํŠธ ๋ณ€ํ™” ํ™•์ธ ๊ฐ€๋Šฅ


โžฐย Storybook ์ฃผ์š” ๊ธฐ๋Šฅ

  • UI ์ปดํฌ๋„ŒํŠธ ์นดํƒˆ๋กœ๊ทธํ™”
  • ์ปดํฌ๋„ŒํŠธ ๋ณ€ํ™” Stories๋กœ ์ €์žฅ
  • ํ•ซ ๋ชจ๋“ˆ ์žฌ๋กœ๋”ฉ๊ณผ ๊ฐ™์€ ๊ฐœ๋ฐœ ํˆด ๊ฒฝํ—˜ ์ œ๊ณต
  • React๋ฅผ ํฌํ•จํ•œ ๋‹ค์–‘ํ•œ ๋ทฐ ๋ ˆ์ด์–ด ์ง€์›

โžฐย Storybook ์‚ฌ์šฉํ•ด๋ณด๊ธฐ

# install
# package.json์„ ๋ณด๊ณ  ์‚ฌ์šฉ์ค‘์ธ FE ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ์— ๋งž๋Š” Storybook ์‚ฌ์šฉํ™˜๊ฒฝ์„ ์•Œ์•„์„œ ๋งŒ๋“ค์–ด์คŒ
npx storybook init

# Storybook ์‹คํ–‰
npm run storybook
// src/Title.js

import React from "react";

const Title = ({ title, textColor }) => (
  <h1 style={{ color: textColor }}>{title}</h1>
);

export default Title;
// src/Title.stories.js

import Title from "./Title";

export default {
  title: "Practice/Title", // ์ปดํฌ๋„ŒํŠธ ์ด๋ฆ„์œผ๋กœ, Storybook์—์„œ ์นดํ…Œ๊ณ ๋ฆฌ๋กœ ์ ์šฉ
  component: Title, // ์–ด๋–ค ์ปดํฌ๋„ŒํŠธ๋ฅผ ๊ฐ€์ ธ์™€์„œ Story๋กœ ๋งŒ๋“ค ๊ฒƒ์ธ์ง€ ๋ช…์‹œ
  argTypes: {  // ์ปดํฌ๋„ŒํŠธ์— ํ•„์š”ํ•œ ์ „๋‹ฌ์ธ์ž ์ข…๋ฅ˜&ํƒ€์ž… 
    title: { control: "text" },
    textColor: { control: "text" },
  },
};

// ํ…œํ”Œ๋ฆฟ ์ƒ์„ฑ
// Title ์ปดํฌ๋„ŒํŠธ๊ฐ€ args๋ฅผ ์ „๋‹ฌ๋ฐ›์•„ props๋กœ ๋‚ด๋ ค์คŒ
const Template = (args) => <Title {...args} />;

// Storybook์—์„œ ํ™•์ธํ•˜๊ณ  ์‹ถ์€ ์ปดํฌ๋„ŒํŠธ ์ž‘์„ฑ
// ํ…œํ”Œ๋ฆฟ์„ ์‚ฌ์šฉํ•ด์„œ Storybook์— ๋„ฃ์–ด์ค„ story๋ฅผ ๋งŒ๋“ค์–ด์คŒ
export const RedTitle = Template.bind({});

// ๋งŒ๋“ค์–ด์ค€ story์˜ ์ „๋‹ฌ์ธ์ž ์ž‘์„ฑ
RedTitle.args = {
  title: "Red Title",
  textColor: "red",
};

// Controls ์ง์ ‘ ์„ค์ •๊ฐ€๋Šฅํ•œ Story
export const StorybookTitle = (args) => {
  return <Title {...args} />;
};

// ๋˜ ๋‹ค๋ฅธ Button ์˜ˆ์ œ
// src/Button.js

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

const StyledButton = styled.button`
  // props.color๊ฐ€ ์žˆ์œผ๋ฉด props.color, ์•„๋‹ˆ๋ฉด ํฐ์ƒ‰์„ ๋ฐฐ๊ฒฝ์ƒ‰์œผ๋กœ ์‚ฌ์šฉ
  background: ${(props) => props.color || "white"};

  // props.size๊ฐ€ 'big'์ด๋ฉด 200px, ์•„๋‹ˆ๋ฉด 100px๋ฅผ ๋„ˆ๋น„๋กœ ์‚ฌ์šฉ
  width: ${(props) => (props.size === "big" ? "200px" : "100px")};

  // props.size๊ฐ€ 'big'์ด๋ฉด 80px, ์•„๋‹ˆ๋ฉด 40px๋ฅผ ๋†’์ด๋กœ ์‚ฌ์šฉ
  height: ${(props) => (props.size === "big" ? "80px" : "40px")};
`;

const Button = ({ color, size, text }) => (
  <StyledButton color={color} size={size}>
    {text}
  </StyledButton>
);

export default Button;
// src/Button.stores.js

import Button from "./Button";

export default {
  title: "Practice/Button",
  component: Button,
	// ์–ด๋–ค ํ˜•ํƒœ๋กœ ์ธ์ž๋ฅผ ์ „๋‹ฌํ•ด์ฃผ๋Š”์ง€ ํ™•์ธํ•˜๊ธฐ!
  argTypes: {
    color: { control: "color" },
    size: { control: { type: "radio", options: ["big", "small"] } },
    text: { control: "text" },
  },
};

export const StorybookButton = (args) => <Button {...args}></Button>;


โ˜‘๏ธย useRef

DOM element ์ฃผ์†Œ๊ฐ’์„ ํ™œ์šฉํ•ด์•ผ ํ•˜๋Š” ๊ฒฝ์šฐ, DOM์„ ๊ฑด๋“œ๋ ค์•ผ ํ•  ๋•Œ๊ฐ€ ์ƒ๊ธธ ์ˆ˜ ์žˆ์Œ
์ด๋Ÿฌํ•œ ์˜ˆ์™ธ์ ์ธ ์ƒํ™ฉ์—์„œ useRef๋กœ DOM ๋…ธ๋“œ, element, React ์ปดํฌ๋„ŒํŠธ ์ฃผ์†Œ๊ฐ’์„ ์ฐธ์กฐํ•  ์ˆ˜ ์žˆ์Œ.

// ์–ด๋–ค ์ฃผ์†Œ๊ฐ’์ด๋“  ๋‹ด์„ ์ˆ˜ ์žˆ์Œ.
const ์ฃผ์†Œ๊ฐ’_๋‹ด๋Š”_๊ทธ๋ฆ‡ = useRef(์ฐธ์กฐ์ž๋ฃŒํ˜•);

return(
	<div>
		<input ref={์ฃผ์†Œ๊ฐ’_๋‹ด๋Š”_๊ทธ๋ฆ‡} type="text" />
		{/* ์ฃผ์†Œ๊ฐ’_๋‹ด๋Š”_๊ทธ๋ฆ‡ ๋ณ€์ˆ˜์— input DOM element ์ฃผ์†Œ๊ฐ€ ๋‹ด๊น€ */}
		{/* ๋‹ค๋ฅธ ์ปดํฌ๋„ŒํŠธ์—์„œ input DOM element ํ™œ์šฉ ๊ฐ€๋Šฅ */}
	</div>
);

โœ‹ย ์ด๋Ÿฌํ•œ ์ฃผ์†Œ๊ฐ’์€ ์ปดํฌ๋„ŒํŠธ๊ฐ€ re-render๋˜๋„ ๋ฐ”๋€Œ์ง€ ์•Š์Œ.

// useRef ํ™œ์šฉ ์˜ˆ์ œ

function InputFocusButton() {
	const inputEl = useRef(null);
	const onButtonClick = () => {
		inputEl.current.focus();
	};
	return (
		<>
			<input ref={inputEl} type="text" />
			<button onClick={onButtonClick}>Focus the input</button>
		</>
	);
}

์˜ค๋Š˜๋„ ๋ฐ–์—์„œ ๋ฐฅ ๋จน๊ณ  ์˜ค๋Š” ๋ฐ”๋žŒ์— ์ €๋… ๊ณต๋ถ€ ์กฐ๊ธˆ ๋Šฆ๊ฒŒ ์‹œ์ž‘..
ํ•  ๊ณต๋ถ€๊ฐ€ ๋„˜ ๋งŽ๋‹ค. ๋งจ๋‚  ๊ณ„ํš๋งŒ ์žฅํ™ฉํ•˜๊ฒŒ ์„ธ์›Œ๋†“๊ณ  ๋‹ค ์ง€ํ‚ค์ง€๋„ ๋ชปํ•จ;๐Ÿซ 

โ˜‘๏ธ ํ”„๋กœ๊ทธ๋ž˜๋จธ์Šค Lv.1๊ฐ™์€ ์ˆซ์ž๋Š” ์‹ซ์–ด ๋ฌธ์ œ ํ’€๊ธฐ
โ˜‘๏ธ ํ•œ์ž… ๋ฆฌ์•กํŠธ JS ์‘์šฉ ํŒŒํŠธ ๊ฐ•์˜ ๋“ฃ๊ธฐ
โ˜‘๏ธ Coplit ๋ฐฐ์—ด ๋ฌธ์ œ ๋ณต์Šต
โ˜‘๏ธ Udemy ์•Œ๊ณ ๋ฆฌ์ฆ˜&์ž๋ฃŒ๊ตฌ์กฐ
๋น…์˜คํ‘œ๊ธฐ๋ฒ• ๊ฐ•์˜ ๋“ฃ๊ธฐ
โ˜‘๏ธ Udemy React_Section 1 ๊ฐ•์˜ ๋“ฃ๊ธฐ

profile
FE developer

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