์—ฌ๋Ÿฌ interface ํƒ€์ž…์„ ์กฐ๊ฑด๋ณ„๋กœ ํ•˜๋‚˜์˜ ํƒ€์ž… ์•ˆ์—์„œ ์ •์˜ํ•˜๊ณ  ์‹ถ์„ ๋•Œ
export enum SearchType {
  FRUIT = โ€˜FRUITโ€™,
  FOOD = โ€˜FOODโ€™,
  CLOTHES = โ€˜CLOTHESโ€™,
  SHOES = โ€˜SHOESโ€™,
  BAGS = โ€˜BAGSโ€™,
}

type TypeName<T> = T extends SearchType.FRUIT
  ? FruitItem
  : T extends SearchType.FOOD
  ? FoodItem
  : T extends SearchType.CLOTHES
  ? ClothesItem
  : T extends SearchType.SHOES
  ? ShoesItem
  : BagsItem;


์‚ฌ์šฉ ์Šคํƒ ๋ฐ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ: React, lodash

 

์–˜ ์ข€ ๊ท€์—ฝ๋„ค ์ฒธ์‹œ? ์ฒธ์„ธ์ด?

 
 

Debounce ์‚ฌ์šฉ ๋ชฉ์ : ๊ฒ€์ƒ‰์‹œ input์˜ onChange๋งˆ๋‹ค ํ•จ์ˆ˜๊ฐ€ ํ˜ธ์ถœ๋˜๋Š” ๊ฒƒ์„ debounce๋ฅผ ํ†ตํ•ด ๋ฐฉ์ง€

 

 

1. Input์˜ onChange๋ฅผ ํ†ตํ•œ api ํ˜ธ์ถœ

 
์•„๋ž˜ ํ•จ์ˆ˜๋ฅผ ์‚ดํŽด๋ณด์ž.
 

 
 
 
 
์ด ํ•จ์ˆ˜๋Š” input์— ํ…์ŠคํŠธ๋ฅผ ์ž…๋ ฅํ•  ๊ฒฝ์šฐ input์˜ onChange๋ฅผ ํ†ตํ•ด ํฌ์ผ“๋ชฌ์„ ์กฐํšŒํ•˜๋Š” api๋ฅผ ํ˜ธ์ถœํ•œ๋‹ค.

input์˜ onChange๋Š” input์— ๊ฐ’์ด ์ž…๋ ฅ๋  ๋•Œ๋งˆ๋‹ค ํ˜ธ์ถœ๋˜๊ธฐ ๋•Œ๋ฌธ์— ๊ธ€์ž ์ˆ˜ ๋งŒํผ handleSearch ํ•จ์ˆ˜๊ฐ€ ํ˜ธ์ถœ๋˜๋Š” ๊ฒƒ์„ ์•„๋ž˜์—์„œ ๋ณผ ์ˆ˜ ์žˆ๋‹ค. (๊ฒ€์ƒ‰ ์„ฑ๋Šฅ ์ €ํ•˜)


 

 
 
์ด๋ฅผ ๋ฐฉ์ง€ํ•˜๊ธฐ ์œ„ํ•ด lodash์˜ debounce ํ•จ์ˆ˜๋ฅผ ์ ์šฉํ•ด ๋ณผ ๊ฒƒ์ด๋‹ค.

๐Ÿ’กLodash๋ž€? A modern JavaScript utility library delivering modularity, performance & extras. (๊ณต์‹ ๋ฌธ์„œ์—์„œ ์ •์˜ํ•˜๊ณ  ์žˆ๋Š” lodash์˜ ์˜๋ฏธ์ด๋‹ค; ๋ชจ๋“ˆ์„ฑ, ์„ฑ๋Šฅ๊ณผ ์ถ”๊ฐ€ ๊ธฐ๋Šฅ ๋“ฑ์„ ์ œ๊ณตํ•˜๋Š” ๋ชจ๋˜ ์ž๋ฐ”์Šคํฌ๋ฆฝํŠธ ์œ ํ‹ธ๋ฆฌํ‹ฐ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ์ด๋‹ค.)



2. Lodash์˜ debounce ์ ์šฉ

$ npm i -g npm //npm ์„ค์น˜ ์™„๋ฃŒ์‹œ ์ƒ๋žต
$ npm i --save lodash


์œ„ ๋ช…๋ น์–ด๋ฅผ ํ†ตํ•ด lodash๋ฅผ ์„ค์น˜ํ•œ๋‹ค.


 

Creates a debounced function that delays invoking func until after wait milliseconds have elapsed since the last time the debounced function was invoked.
 
 
 

import { debounce } from 'lodash';



ํ•„์š”ํ•œ ํ•จ์ˆ˜ debounce๋งŒ ๊ตฌ์กฐ๋ถ„ํ•ด๋กœ importํ•œ๋‹ค. (์ „์ฒด lodash๋ฅผ importํ•˜๋Š” ๊ฒƒ๋ณด๋‹ค ๋ฉ”๋ชจ๋ฆฌ๊ฐ€ ํ›จ์”ฌ ์ ๋‹ค)
 
 

   const getPokemon = debounce(async (value: string) => {
    await axios
      .get(`https://pokeapi.co/api/v2/pokemon/${value}`)
      .then((res) => {
        setPokemon(res);
      })
      .catch((err) => {
        return;
      });
  }, 300);

 
 
 
๊ทธ๋Ÿฐ ๋‹ค์Œ ๊ธฐ์กด getPokemon ํ•จ์ˆ˜๋ฅผ debounce ํ•จ์ˆ˜๋กœ ๊ฐ์‹ธ์ค€๋’ค ์ง€์—ฐ์‹œ๊ฐ„์„ ์ˆซ์ž๋กœ ์ ์–ด์ค€๋‹ค. (์œ„ ์˜ˆ์‹œ์—์„œ๋Š” 0.3์ดˆ๋กœ ์„ค์ •) 
 
 
์ด๋ ‡๊ฒŒ ํ•˜๋ฉด input์— ํƒ€์ดํ•‘์ด ๋˜๋”๋ผ๋„ ํ•จ์ˆ˜ ํ˜ธ์ถœ์„ 0.3์ดˆ๋งˆ๋‹ค ํ•˜๋Š” ๊ฒƒ์„ ๋ณผ ์ˆ˜ ์žˆ๋‹ค.
 
 

 3. State ๋ณ€๊ฒฝ๊ณผ debounce ๋™์‹œ ์ ์šฉ

๊ทธ๋ ‡๋‹ค๋ฉด ๋งŒ์•ฝ state ๋ณ€๊ฒฝ๊ณผ debouce๋ฅผ ํ•จ๊ป˜ ํ˜ธ์ถœํ•  ๊ฒฝ์šฐ debounce๋Š” ํšจ๊ณผ์ ์œผ๋กœ ์ž‘๋™ํ• ๊นŒ?


์•„๋ž˜ handleSearch ํ•จ์ˆ˜๋Š” input์˜ onChange๊ฐ€ ํ˜ธ์ถœ๋  ๋•Œ๋งˆ๋‹ค(๊ฐ’์ด ๋ณ€๊ฒฝ๋  ๋•Œ๋งˆ๋‹ค) ์‹คํ–‰๋œ๋‹ค.

handleSearch๋‚ด์—์„œ setText๋ฅผ ํ†ตํ•ด ๋ณ€ํ•˜๋Š” input๊ฐ’์„ ๋™์‹œ์— ์ €์žฅํ•˜๊ณ , debounce๋ฅผ ํ†ตํ•ด api๋ฅผ ํ˜ธ์ถœํ•˜๋ฉด ์•„๋ž˜์™€ ๊ฐ™์ด ํ•จ์ˆ˜๊ฐ€ ๋งŒ๋“ค์–ด์ง„๋‹ค.
 

const getPokemon = debounce(async (value: string) => {
    await axios
      .get(`https://pokeapi.co/api/v2/pokemon/${value}`)
      .then((res) => {
        setPokemon(res);
      })
      .catch((err) => {
        return;
      });
  }, 300);

const handleSearch = (e) => {
  setText(e.target.value);
  getPokemon(e.target.value);
}



์œ„ ํ•จ์ˆ˜์—์„œ ๋ฌธ์ œ์ ์€ ์šฐ๋ฆฌ์˜ ์˜ˆ์ƒ๊ณผ ๋‹ค๋ฅด๊ฒŒ getPokemonํ•จ์ˆ˜๊ฐ€ 0.3์ดˆ๋งˆ๋‹ค๊ฐ€ ์•„๋‹Œ input์˜ value๊ฐ€ ๋ฐ”๋€”๋•Œ๋งˆ๋‹ค ํ˜ธ์ถœ๋œ๋‹ค๋Š” ์ ์ด๋‹ค.

์ด ์ฝ”๋“œ์˜ ๋ฌธ์ œ์ ์€ setText ํ•จ์ˆ˜๋ฅผ ์‹คํ–‰ํ•  ๋•Œ๋งˆ๋‹ค ์ปดํฌ๋„ŒํŠธ๊ฐ€ ์žฌ๋ Œ๋”๋ง๋˜์–ด debounceํ•จ์ˆ˜๋ฅผ ํ˜ธ์ถœํ•˜๋Š” getPokemonํ•จ์ˆ˜๋ฅผ ์žฌ์ƒ์„ฑํ•œ๋‹ค๋Š” ์ ์ด๋‹ค.
 

 4. ์ปดํฌ๋„ŒํŠธ ์žฌ๋ Œ๋”๋ง์— ๊ด€๊ณ„์—†์ด debounce ํ•จ์ˆ˜ ์‹คํ–‰ํ•˜๊ธฐ

const getPokemon = useCallback(debounce(async (value: string) => {
    await axios
      .get(`https://pokeapi.co/api/v2/pokemon/${value}`)
      .then((res) => {
        setPokemon(res);
      })
      .catch((err) => {
        return;
      });
  }, 300),
  []
;

const handleSearch = (e) => {
  setText(e.target.value);
  getPokemon(e.target.value);
}


์ •๋‹ต์€ useCallback ํ•จ์ˆ˜๋กœ debounceํ•จ์ˆ˜๋ฅผ ๊ฐ์‹ธ์ฃผ๋Š” ๊ฒƒ์ด๋‹ค.

์œ„์˜ getPokemon ํ•จ์ˆ˜๋Š” handleSearch์—์„œ text๊ฐ€ ๋ณ€๊ฒฝ์ด ๋˜์–ด๋„ ์ด ๋ณ€์ˆ˜๋ฅผ ๊ตฌ๋…ํ•˜์ง€ ์•Š๊ธฐ ๋•Œ๋ฌธ์— debounceํ•จ์ˆ˜๋ฅผ ์žฌ์ƒ์„ฑํ•˜์ง€ ์•Š๋Š”๋‹ค.



 

์›๋ฌธ: https://marmelab.com/blog/2024/01/23/react-19-new-hooks.html

 

 

์ผ๋ฐ˜์ ์ธ ์ƒ๊ฐ๊ณผ ๋‹ฌ๋ฆฌ React coreํŒ€์€ ๋ฆฌ์•กํŠธ ์„œ๋ฒ„ ์ปดํฌ๋„ŒํŠธ์™€ Next.js์—๋งŒ ์˜ค์ง ์ดˆ์ ์„ ๋‘์ง„ ์•Š๋Š”๋‹ค. ์ƒˆ๋กœ์šด client-side ํ›…๋“ค์ด ๋‹ค์Œ React ๋ฉ”์ธ ๋ฒ„์ „์ธ 19๋ฒ„์ „์— ๋„์ž…๋œ๋‹ค. ๊ทธ๋“ค์€ ๋ฆฌ์•กํŠธ์˜ ๋‘ ๊ฐ€์ง€ ์ฃผ์š” ๋ฌธ์ œ์ , ์ฆ‰ ๋ฐ์ดํ„ฐ ๊ฐ€์ ธ์˜ค๊ธฐ(data fetching)๊ณผ ํผ(form)์— ์ดˆ์ ์„ ๋งž์ถ”๊ณ  ์žˆ๋‹ค. ์ด ํ›…๋“ค์€ ์‹ฑ๊ธ€ ํŽ˜์ด์ง€ ์–ดํ”Œ๋ฆฌ์ผ€์ด์…˜ ์ž‘์—…์„ ํ•˜๋Š” ๊ฐœ๋ฐœ์ž๋ฅผ ํฌํ•จํ•ด React ๊ฐœ๋ฐœ์ž๋“ค์˜ ์ƒ์‚ฐ์„ฑ์„ ํ–ฅ์ƒ์‹œ์ผœ์ค„ ๊ฒƒ์ด๋‹ค.

 

๋” ์ด์ƒ ๊ณ ๋ฏผํ•˜์ง€ ๋ง๊ณ , ์ƒˆ๋กœ์šด ํ›…๋“ค์„ ์‚ดํŽด๋ณด์ž!

 

 

์ฃผ๋ชฉ: ์ด ํ›…๋“ค์€ React์˜ Canary์™€ ์‹คํ—˜์  ์ฑ„๋„์—์„œ๋งŒ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๋‹ค. ์ด ํ›…๋“ค์€ ๊ณง ์ถœ์‹œ๋  ๋ฆฌ์•กํŠธ 19์— ํฌํ•จ๋˜์ง€๋งŒ, API๋Š” ์ตœ์ข… ์ถœ์‹œ ์ „์— ๋ณ€๊ฒฝ๋  ์ˆ˜ ์žˆ๋‹ค.

 

 

use(Promise)

 

์ด ์ƒˆ๋กœ์šด ํ›…์€ ํด๋ผ์ด์–ธํŠธ์˜ 'suspending'์„ ์œ„ํ•œ ๊ณต์‹ API์ด๋‹ค. ๋‹น์‹ ์€ ๊ทธ๊ฒƒ์„ promise๋กœ ๋„˜๊ธธ ์ˆ˜ ์žˆ๊ณ  ๋ฆฌ์•กํŠธ๋Š” ๊ทธ๊ฒƒ์ด ํ•ด๊ฒฐ๋  ๋•Œ๊นŒ์ง€ ๊ทธ๊ฒƒ์„ ์ค‘๋‹จ์‹œํ‚ฌ ๊ฒƒ์ด๋‹ค. React use ๋ฌธ์„œ์—์„œ ๊ฐ€์ ธ์˜จ ๊ธฐ๋ณธ ๊ตฌ๋ฌธ์€ ๋‹ค์Œ๊ณผ ๊ฐ™๋‹ค.

 

import { use } from 'react';

function MessageComponent({ messagePromise }) {
    const message = use(messagePromise);
    // ...
}

 

์ข‹์€ ์†Œ์‹์€ ์ด ํ›…์ด ๋ฐ์ดํ„ฐ ํŒจ์นญ์— ์‚ฌ์šฉ๋  ์ˆ˜ ์žˆ๋‹ค๋Š” ๊ฒƒ์ด๋‹ค. ์—ฌ๊ธฐ ๋งˆ์šดํŠธ์‹œ์™€ ๋ฒ„ํŠผ ํด๋ฆญ์‹œ ๋ฐ์ดํ„ฐ ํŒจ์นญ์„ ํ•˜๋Š” ๊ตฌ์ฒด์ ์ธ ์˜ˆ์‹œ๊ฐ€ ์žˆ๋‹ค. ์ด ์ฝ”๋“œ๋Š” ๋‹จ์ผ useEffect๋ฅผ ์‚ฌ์šฉํ•˜์ง€ ์•Š๋Š”๋‹ค:

 

 

 

<Suspense> ๋ฌธ์„œ์˜ ์ด ๊ฒฝ๊ณ ๋ฅผ ๊ธฐ์–ตํ•˜๋Š”๊ฐ€?

 

ํ”„๋ ˆ์ž„์›Œํฌ์˜ ์˜๊ฒฌ ์—†๋Š” Suspense ์ง€์› ๋ฐ์ดํ„ฐ ํŒจ์นญ์€ ์•„์ง ์ง€์›๋˜์ง€ ์•Š๋Š”๋‹ค.

 

์ด๋Š” React19์—์„œ๋Š” ๋” ์ด์ƒ ์‚ฌ์‹ค์ด ์•„๋‹ˆ๋‹ค.

 

์ƒˆ๋กœ์šด use ํ›…์€ ์ˆจ๊ฒจ์ง„ ํž˜์ด ์žˆ๋‹ค: ๋‹ค๋ฅธ ๋ชจ๋“  React Hook๋“ค๊ณผ ๋‹ฌ๋ฆฌ, use๋Š” loop์™€ if์™€ ๊ฐ™์€ ์กฐ๊ฑด ์ ˆ์—์„œ ํ˜ธ์ถœํ•  ์ˆ˜ ์žˆ๋‹ค.

 

์ด ๋ง์ด ์ฆ‰, ํด๋ผ์ด์–ธํŠธ ์ธก์—์„œ ๋ฐ์ดํ„ฐ๋ฅผ ๊ฐ€์ ธ์˜ค๊ธฐ ์œ„ํ•ด TanStack Query์™€ ๊ฐ™์€ ์„œ๋“œํŒŒํ‹ฐ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ๋ฅผ ๋” ์ด์ƒ ์‚ฌ์šฉํ•  ํ•„์š”๊ฐ€ ์—†์Œ์„ ์˜๋ฏธํ• ๊นŒ? TanStack Query๊ฐ€ ๋‹จ์ˆœํžˆ Promise๋ฅผ ํ•ด๊ฒฐํ•˜๋Š” ๊ฒƒ ์ด์ƒ์˜ ์—ญํ• ์„ ํ•˜๊ธฐ ๋•Œ๋ฌธ์— ๋” ๋‘๊ณ  ๋ด์•ผ ํ•œ๋‹ค.

 

ํ•˜์ง€๋งŒ ๊ทธ๊ฒƒ์€ ์˜ฌ๋ฐ”๋ฅธ ๋ฐฉํ–ฅ์œผ๋กœ ๋‚˜์•„๊ฐ€๋Š” ํ›Œ๋ฅญํ•œ ๋‹จ๊ณ„์ด๋ฉฐ REST ๋˜๋Š” GraphQL API๋ฅผ ๊ธฐ๋ฐ˜์œผ๋กœ ํ•œ ์‹ฑ๊ธ€ ํŽ˜์ด์ง€ ์–ดํ”Œ๋ฆฌ์ผ€์ด์…˜์„ ์‰ฝ๊ฒŒ ๋งŒ๋“ค ์ˆ˜ ์žˆ์„ ๊ฒƒ์ด๋‹ค. ๋‚˜๋Š” ์ด ์ƒˆ๋กœ์šด ํ›…์— ๋งค์šฐ ์—ด๊ด‘ํ•œ๋‹ค!

 

React ๋ฌธ์„œ์—์„œ use(Promise) ํ›…์— ๋Œ€ํ•œ ์ž์„ธํ•œ ๋‚ด์šฉ์„ ์ฝ์–ด๋ณด์•„๋ผ.

 

use(Context)

React Context๋ฅผ ์ฝ๋Š”๋ฐ ๊ฐ™์€ use ํ›…์„ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๋‹ค. ๋ฃจํ”„ ์•ˆ์—์„œ ํ˜ธ์ถœํ•  ์ˆ˜ ์žˆ์œผ๋ฉฐ if์™€ ๊ฐ™์€ ์กฐ๊ฑด๋ฌธ์„ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๋‹ค๋Š” ์ ์„ ์ œ์™ธํ•˜๋ฉด ์ด๋Š” ์ •ํ™•ํžˆ useContext์™€ ๊ฐ™๋‹ค.

 

 

import { use } from 'react';

function HorizontalRule({ show }) {
    if (show) {
        const theme = use(ThemeContext);
        return <hr className={theme} />;
    }
    return false;
}

 

๋ฃจํ”„ ํ˜น์€ ์กฐ๊ฑด์ ˆ์—์„œ ์ปจํ…์ŠคํŠธ๋ฅผ ์ฝ๋Š” ์œ ์ผํ•œ ๋ฐฉ๋ฒ•์ด ์ปดํฌ๋„ŒํŠธ๋ฅผ ๋‘˜๋กœ ๋‚˜๋ˆ„๋Š” ๊ฒƒ์ด๊ธฐ ๋•Œ๋ฌธ์— ์ด๊ฒƒ์€ ์ผ๋ถ€ ์‚ฌ์šฉ ์‚ฌ๋ก€์— ๋Œ€ํ•œ ์ปดํฌ๋„ŒํŠธ ๊ณ„์ธต ๊ตฌ์กฐ๋ฅผ ๋‹จ์ˆœํ™”ํ•  ๊ฒƒ์ด๋‹ค.

 

์ปจํ…์ŠคํŠธ๊ฐ€ ๋ฐ”๋€Œ์—ˆ๋”๋ผ๋„ ์ปดํฌ๋„ŒํŠธ์˜ ๋ฆฌ๋ Œ๋”๋ง์„ ์กฐ๊ฑด์ ์œผ๋กœ ๊ฑด๋„ˆ๋›ธ ์ˆ˜ ์žˆ๊ธฐ ๋•Œ๋ฌธ์— ์„ฑ๋Šฅ ์ธก๋ฉด์—์„œ๋„ ํฐ ํ˜๋ช…์ด ๋  ์ˆ˜ ์žˆ๋‹ค.

 

React ๋ฌธ์„œ์—์„œ use(Context) ํ›…์— ๋Œ€ํ•œ ์ž์„ธํ•œ ๋‚ด์šฉ์„ ์ฝ์–ด๋ณด์•„๋ผ.

 

Form Actions

 

์ด ์ƒˆ๋กœ์šด ๊ธฐ๋Šฅ์„ ์‚ฌ์šฉํ•˜๋ฉด ํ•จ์ˆ˜๋ฅผ <form>์˜ ์•ก์…˜ ํ”„๋กญ์— ์ „๋‹ฌํ•  ์ˆ˜ ์žˆ๋‹ค. ํผ์ด ์ œ์ถœ๋˜๋ฉด React๋Š” ์ด ํ•จ์ˆ˜๋ฅผ ํ˜ธ์ถœํ•œ๋‹ค:

 

 

 

 

๋งŒ์•ฝ ๋‹น์‹ ์ด <form action> ํ”„๋กญ์„ React18์—์„œ ์ถ”๊ฐ€ํ•œ๋‹ค๋ฉด ๋‹น์‹ ์€ ๊ฒฝ๊ณ (warning)๋ฅผ ๋ฐ›๊ฒŒ ๋  ๊ฒƒ์„ ๊ธฐ์–ตํ•˜๋ผ:

 

Warning: Invalid value for prop action on <form> tag. Either remove it from the element or pass a string or number value to keep it in the DOM.

 

๋‹ค์Œ๊ณผ ๊ฐ™์€ form์„ ์ž‘์„ฑํ•  ์ˆ˜ ์žˆ๋Š” React 19์—์„œ ์ด ๊ฒฝ๊ณ ๋Š” ๋” ์ด์ƒ ์‚ฌ์‹ค์ด ์•„๋‹ˆ๋‹ค.

 

import { useState } from 'react';

const AddToCartForm = ({ id, title, addToCart }) => {
  const formAction = async (formData) => {
    try {
      await addToCart(formData, title);
    } catch (e) {
      // show error notification
    }
  };

  return (
    <form action={formAction}>
      <h2>{title}</h2>
      <input type="hidden" name="itemID" value={id} />
      <button type="submit">Add to Cart</button>
    </form>
  );
};

type Item = {
  id: string;
  title: string;
};

const Cart = ({ cart }: { cart: Item[] }) => {
  if (cart.length == 0) {
    return null;
  }
  return (
    <>
      Cart content:
      <ul>
        {cart.map((item, index) => (
          <li key={index}>{item.title}</li>
        ))}
      </ul>
      <hr />
    </>
  );
};

export const App = () => {
  const [cart, setCart] = useState<Item[]>([]);

  const addToCart = async (formData: FormData, title) => {
    const id = String(formData.get('itemID'));
    // simulate an AJAX call
    await new Promise((resolve) => setTimeout(resolve, 1000));
    setCart((cart: Item[]) => [...cart, { id, title }]);

    return { id };
  };

  return (
    <>
      <Cart cart={cart} />
      <AddToCartForm
        id="1"
        title="JavaScript: The Definitive Guide"
        addToCart={addToCart}
      />
      <AddToCartForm
        id="2"
        title="JavaScript: The Good Parts"
        addToCart={addToCart}
      />
    </>
  );
};

 

accToCart ํ•จ์ˆ˜๋Š” ์„œ๋ฒ„ Action์ด ์•„๋‹ˆ๋‹ค. ์ด๊ฒƒ์€ ํด๋ผ์ด์–ธํŠธ ์ธก์—์„œ ํ˜ธ์ถœ๋˜๋ฉฐ ๋น„๋™๊ธฐ ๊ธฐ๋Šฅ์ผ ์ˆ˜ ์žˆ๋‹ค.

 

์ด๋ ‡๊ฒŒ ํ•˜๋ฉด ๋ฆฌ์•กํŠธ์—์„œ ๊ฒ€์ƒ‰ ํผ๊ณผ ๊ฐ™์€ AJAX ํผ์˜ ์ฒ˜๋ฆฌ๊ฐ€ ํฌ๊ฒŒ ๊ฐ„๋‹จํ•ด์งˆ ๊ฒƒ์ด๋‹ค. ๊ทธ๋Ÿฌ๋‚˜ ์ด๊ฒƒ์€ ์–‘์‹ ์ œ์ถœ(์œ ํšจ์„ฑ ํ™•์ธ, ์‚ฌ์ด๋“œ ์ดํŽ™ํŠธ ๋“ฑ)์„ ์ฒ˜๋ฆฌํ•˜๋Š” ๊ฒƒ ์ด์ƒ์˜ ์ผ์„ ํ•˜๋Š” React Hook Form๊ณผ ๊ฐ™์€ ์„œ๋“œํŒŒํ‹ฐ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ๋ฅผ ์—†์•จ๋งŒํผ ์ถฉ๋ถ„ํ•˜์ง€ ์•Š์„ ์ˆ˜ ์žˆ๋‹ค. 

 

Tip: ๋‹น์‹ ์€ ์œ„ ์˜ˆ์ œ์—์„œ ๋ช‡๋ช‡ ์‚ฌ์šฉ์„ฑ ๋ฌธ์ œ๋ฅผ ๋ฐœ๊ฒฌํ•  ์ˆ˜ ์žˆ๋‹ค. (submit์„ ์ง„ํ–‰ํ•  ๋•Œ submit ๋ฒ„ํŠผ์ด ํ™œ์„ฑํ™”๋˜์ง€ ์•Š์Œ, ํ™•์ธ ๋ฉ”์„ธ์ง€ ๋ˆ„๋ฝ, ๋Šฆ์€ ์นดํŠธ ์—…๋ฐ์ดํŠธ). ๋‹คํ–‰ํžˆ๋„ ๋” ๋งŽ์€ ํ›…๋“ค์ด ์ด๋Ÿฌํ•œ ์‚ฌ์šฉ ์‚ฌ๋ก€๋ฅผ ๋•๊ธฐ ์œ„ํ•ด ์ œ๊ณต๋˜๊ณ  ์žˆ๋‹ค. ๊ณ„์† ์ฝ์–ด๋ณด๊ธธ!

 

 

React ๋ฌธ์„œ์—์„œ the <form action> prop์— ๋Œ€ํ•œ ์ž์„ธํ•œ ๋‚ด์šฉ์„ ์ฝ์–ด๋ณด์•„๋ผ.

 

 

useFormState

 

์ด ์ƒˆ๋กœ์šด ํ›…์€ ์•„๋ž˜ ๋ฌ˜์‚ฌํ•œ ๊ฒƒ์ฒ˜๋Ÿผ ๋น„๋™๊ธฐ ํผ ์•ก์…˜์„ ๋•๋Š” ์—ญํ• ์„ ํ•œ๋‹ค. useFormState๋ฅผ ํ˜ธ์ถœํ•ด ํผ์ด ์ œ์ถœ๋œ ๋งˆ์ง€๋ง‰ ์‹œ์ ๋ถ€ํ„ฐ ์•ก์…˜์˜ ๋ฐ˜ํ™˜ ๊ฐ’์— ์ ‘๊ทผํ•œ๋‹ค.

 

import { useFormState } from 'react-dom';
import { action } from './action';

function MyComponent() {
    const [state, formAction] = useFormState(action, null);
    // ...
    return <form action={formAction}>{/* ... */}</form>;
}

 

 

์˜ˆ๋ฅผ ๋“ค์–ด, ์ด๊ฒƒ์€ ๋‹น์‹ ์ด ํผ ์•ก์…˜์—์„œ ๋ฐ˜ํ™˜๋œ ํ™•์ธ ํ˜น์€ ์—๋Ÿฌ ๋ฉ”์„ธ์ง€๋ฅผ ๋ณด์—ฌ์ฃผ๊ฒŒ ํ•œ๋‹ค.

 

import { useState } from 'react';
import { useFormState } from 'react-dom';

const AddToCartForm = ({ id, title, addToCart }) => {
  const addToCartAction = async (prevState, formData) => {
    try {
      await addToCart(formData, title);
      return 'Added to cart';
    } catch (e) {
      return "Couldn't add to cart: the item is sold out.";
    }
  };

  const [message, formAction] = useFormState(addToCartAction, null);

  return (
    <form action={formAction}>
      <h2>{title}</h2>
      <input type="hidden" name="itemID" value={id} />
      <button type="submit">Add to Cart</button>&nbsp;
      {message}
    </form>
  );
};

type Item = {
  id: string;
  title: string;
};

export const App = () => {
  const [cart, setCart] = useState<Item[]>([]);

  const addToCart = async (formData: FormData, title) => {
    const id = String(formData.get('itemID'));
    // simulate an AJAX call
    await new Promise((resolve) => setTimeout(resolve, 1000));
    if (id === '1') {
      setCart((cart: Item[]) => [...cart, { id, title }]);
    } else {
      throw new Error('Unavailable');
    }

    return { id };
  };

  return (
    <>
      <AddToCartForm
        id="1"
        title="JavaScript: The Definitive Guide"
        addToCart={addToCart}
      />
      <AddToCartForm
        id="2"
        title="JavaScript: The Good Parts"
        addToCart={addToCart}
      />
    </>
  );
};

 

 

์ฃผ๋ชฉ: useFormState๋Š” react๊ฐ€ ์•„๋‹ˆ๋ผ react-dom์—์„œ ๋ถ€ํ„ฐ import๋˜์–ด์•ผ ํ•œ๋‹ค.

 

 

React ๋ฌธ์„œ์—์„œ useFormState์— ๋Œ€ํ•œ ์ž์„ธํ•œ ๋‚ด์šฉ์„ ์ฝ์–ด๋ณด์•„๋ผ.

 

 

 

useFormStatus

 

useFormStatus๋ฅผ ์‚ฌ์šฉํ•˜๋ฉด ๋ถ€๋ชจ <form>์ด ํ˜„์žฌ ์ œ์ถœ ์ค‘์ด๊ฑฐ๋‚˜ ์„ฑ๊ณต์ ์œผ๋กœ ์ œ์ถœํ–ˆ๋Š”์ง€ ์•Œ ์ˆ˜ ์žˆ๋‹ค. ํผ์˜ ์ž์‹์—์„œ ํ˜ธ์ถœํ•  ์ˆ˜ ์žˆ์œผ๋ฉฐ ๋‹ค์Œ ์†์„ฑ์„ ๊ฐ€์ง„ ๊ฐœ์ฒด๋ฅผ ๋ฐ˜ํ™˜ํ•œ๋‹ค:

 

const { pending, data, method, action } = useFormStatus();

 

 

๋‹น์‹ ์€ ๋ฐ์ดํ„ฐ ์†์„ฑ์„ ํ†ตํ•ด ์œ ์ €๊ฐ€ ์ œ์ถœ ์ค‘์ธ ๋ฐ์ดํ„ฐ๋ฅผ ํ‘œ์‹œํ•  ์ˆ˜ ์žˆ๋‹ค. ํผ์ด ์ œ์ถœ๋˜๋Š” ๋™์•ˆ ๋ฒ„ํŠผ์ด ๋น„ํ™œ์„ฑํ™”๋œ pending ์ƒํƒœ ๋˜ํ•œ ์•„๋ž˜ ์˜ˆ์‹œ์™€ ๊ฐ™์ด ํ‘œ์‹œํ•  ์ˆ˜ ์žˆ๋‹ค:

 

import { useState } from 'react';
import { useFormStatus } from 'react-dom';

const AddToCartForm = ({ id, title, addToCart }) => {
  const formAction = async (formData) => {
    try {
      await addToCart(formData, title);
    } catch (e) {
      // show error notification
    }
  };

  return (
    <form action={formAction}>
      <h2>{title}</h2>
      <input type="hidden" name="itemID" value={id} />
      <SubmitButton />
    </form>
  );
};

const SubmitButton = () => {
  const { pending } = useFormStatus();
  return (
    <button disabled={pending} type="submit">
      Add to Cart
    </button>
  );
};

type Item = {
  id: string;
  title: string;
};

const Cart = ({ cart }: { cart: Item[] }) => {
  if (cart.length == 0) {
    return null;
  }
  return (
    <>
      Cart content:
      <ul>
        {cart.map((item, index) => (
          <li key={index}>{item.title}</li>
        ))}
      </ul>
      <hr />
    </>
  );
};

export const App = () => {
  const [cart, setCart] = useState<Item[]>([]);

  const addToCart = async (formData: FormData, title) => {
    const id = String(formData.get('itemID'));
    // simulate an AJAX call
    await new Promise((resolve) => setTimeout(resolve, 1000));
    setCart((cart: Item[]) => [...cart, { id, title }]);

    return { id };
  };

  return (
    <>
      <Cart cart={cart} />
      <AddToCartForm
        id="1"
        title="JavaScript: The Definitive Guide"
        addToCart={addToCart}
      />
      <AddToCartForm
        id="2"
        title="JavaScript: The Good Parts"
        addToCart={addToCart}
      />
    </>
  );
};

 

 

์ฃผ๋ชฉ: useFormStatus๋Š” react๊ฐ€ ์•„๋‹Œ react-dom์—์„œ importํ•ด์•ผ ํ•œ๋‹ค. ๋˜ํ•œ ๋ถ€๋ชจ ํผ์ด ์œ„์—์„œ ์„ค๋ช…ํ•œ action prop์„ ์‚ฌ์šฉํ•  ๋•Œ๋งŒ ์ž‘๋™ํ•œ๋‹ค.

 

์ด ํ›…์€ useFormState์™€ ํ•จ๊ป˜ ๋ถˆํ•„์š”ํ•œ ์ปจํ…์ŠคํŠธ ํšจ๊ณผ๋กœ ์ปดํฌ๋„ŒํŠธ๋ฅผ ์–ด์ˆ˜์„ ํ•˜๊ฒŒ ๋งŒ๋“ค์ง€ ์•Š๊ณ  ํด๋ผ์ด์–ธํŠธ ์ธก ํผ์˜ ์œ ์ € ๊ฒฝํ—˜์„ ํ–ฅ์ƒ์‹œํ‚ฌ ๊ฒƒ์ด๋‹ค. useFormStatus ํ›„ํฌ์— ๋Œ€ํ•œ ์ž์„ธํ•œ ๋‚ด์šฉ์€ React ๋ฌธ์„œ์—์„œ ํ™•์ธํ•  ์ˆ˜ ์žˆ๋‹ค.

 

 

useOptimistic

 

์ด ์ƒˆ๋กœ์šด ํ›…์€ actioin์ด ์ œ์ถœ๋˜๋Š” ๋™์•ˆ ์‚ฌ์šฉ์ž ์ธํ„ฐํŽ˜์ด์Šค๋ฅผ ์ตœ์ ์œผ๋กœ ์—…๋ฐ์ดํŠธํ•  ์ˆ˜ ์žˆ๊ฒŒ ํ•œ๋‹ค. 

 

 

import { useOptimistic } from 'react';

function AppContainer() {
    const [optimisticState, addOptimistic] = useOptimistic(
        state,
        // updateFn
        (currentState, optimisticValue) => {
            // merge and return new state
            // with optimistic value
        },
    );
}

 

 

์œ„ ์นดํŠธ ์˜ˆ์ œ์—์„œ ์šฐ๋ฆฌ๋Š” AJAX ํ˜ธ์ถœ์ด ์™„๋ฃŒ๋˜๊ธฐ ์ „์— ์ƒˆ ํ•ญ๋ชฉ์ด ์ถ”๊ฐ€๋œ ์นดํŠธ๋ฅผ ํ‘œ์‹œํ•  ์ˆ˜ ์žˆ๋‹ค: 

 

import { useState, useOptimistic } from 'react';

const AddToCartForm = ({ id, title, addToCart, optimisticAddToCart }) => {
  const formAction = async (formData) => {
    optimisticAddToCart({ id, title });
    try {
      await addToCart(formData, title);
    } catch (e) {
      // show error notification
    }
  };

  return (
    <form action={formAction}>
      <h2>{title}</h2>
      <input type="hidden" name="itemID" value={id} />
      <button type="submit">Add to Cart</button>
    </form>
  );
};

type Item = {
  id: string;
  title: string;
};

const Cart = ({ cart }: { cart: Item[] }) => {
  if (cart.length == 0) {
    return null;
  }
  return (
    <>
      Cart content:
      <ul>
        {cart.map((item, index) => (
          <li key={index}>{item.title}</li>
        ))}
      </ul>
      <hr />
    </>
  );
};

export const App = () => {
  const [cart, setCart] = useState<Item[]>([]);

  const [optimisticCart, optimisticAddToCart] = useOptimistic<Item[], Item>(
    cart,
    (state, item) => [...state, item]
  );

  const addToCart = async (formData: FormData, title) => {
    const id = String(formData.get('itemID'));
    // simulate an AJAX call
    await new Promise((resolve) => setTimeout(resolve, 1000));
    setCart((cart: Item[]) => [...cart, { id, title }]);

    return { id };
  };

  return (
    <>
      <Cart cart={optimisticCart} />
      <AddToCartForm
        id="1"
        title="JavaScript: The Definitive Guide"
        addToCart={addToCart}
        optimisticAddToCart={optimisticAddToCart}
      />
      <AddToCartForm
        id="2"
        title="JavaScript: The Good Parts"
        addToCart={addToCart}
        optimisticAddToCart={optimisticAddToCart}
      />
    </>
  );
};

 

 

UI๋ฅผ ์ตœ์ ์œผ๋กœ ์—…๋ฐ์ดํŠธํ•˜๋Š” ๊ฒƒ์€ ์›น ์•ฑ์˜ ์œ ์ € ๊ฒฝํ—˜์„ ํ–ฅ์ƒ์‹œํ‚ค๋Š” ์ข‹์€ ๋ฐฉ๋ฒ•์ด๋‹ค. ์ด ํ›…์€ ์ด ์‚ฌ์šฉ ์‚ฌ๋ก€์— ๋งŽ์€ ๋„์›€์ด ๋œ๋‹ค. useOptimistic์— ๋Œ€ํ•œ ์ž์„ธํ•œ ๋‚ด์šฉ์€ React ๋ฌธ์„œ์—์„œ ์ฝ์„ ์ˆ˜ ์žˆ๋‹ค.

 

 

๋ณด๋„ˆ์Šค: ๋น„๋™๊ธฐ ์ „ํ™˜

React์˜ Transition API๋Š” UI ์ฐจ๋‹จ์—†์ด ์ƒํƒœ๋ฅผ ์—…๋ฐ์ดํŠธํ•  ์ˆ˜ ์žˆ๊ฒŒ ํ•œ๋‹ค. ์˜ˆ๋ฅผ ๋“ค์–ด, ์‚ฌ์šฉ์ž๊ฐ€ ๋งˆ์Œ์„ ๋ฐ”๊ฟ€ ๊ฒฝ์šฐ ์ด์ „ ์ƒํƒœ ๋ณ€๊ฒฝ์„ ์ทจ์†Œํ•  ์ˆ˜ ์žˆ๋‹ค.

 

์ด ์•„์ด๋””์–ด๋Š” startTransition๋ฅผ ํ˜ธ์ถœํ•ด ์ƒํƒœ ๋ณ€ํ™”๋ฅผ ๊ฐ์‹ผ๋‹ค.

 

function TabContainer() {
    const [isPending, startTransition] = useTransition();
    const [tab, setTab] = useState('about');

    function selectTab(nextTab) {
        // instead of setTab(nextTab), put the state change in a transition
        startTransition(() => {
            setTab(nextTab);
        });
    }
    // ...
}

 

๋‹ค์Œ ์˜ˆ๋Š” ์ด Transition API๋ฅผ ์‚ฌ์šฉํ•œ ํƒญ ๋„ค๋น„๊ฒŒ์ด์…˜์„ ๋ณด์—ฌ์ค€๋‹ค. "Posts"์„ ํด๋ฆญํ•œ ๋‹ค์Œ ์ฆ‰์‹œ "Contact"๋ฅผ ํด๋ฆญํ•œ๋‹ค. ์ด๋กœ ์ธํ•ด "Posts"์˜ ๋Š๋ฆฐ ๋ Œ๋”๋ง์ด ์ค‘๋‹จ๋œ๋‹ค. "Contact" ํƒญ์ด ์ฆ‰์‹œ ํ‘œ์‹œ๋œ๋‹ค. ์ด ์ƒํƒœ ์—…๋ฐ์ดํŠธ๋Š” ํŠธ๋žœ์ง€์…˜์œผ๋กœ ํ‘œ์‹œ๋˜๊ธฐ ๋•Œ๋ฌธ์— ๋Š๋ฆฐ ๋ฆฌ๋ Œ๋”(re-render)๋Š” ์‚ฌ์šฉ์ž ์ธํ„ฐํŽ˜์ด์Šค๋ฅผ ํ†ต์ œํ•˜์ง€ ์•Š๋Š”๋‹ค.

 

import { useState, useTransition } from 'react';
import TabButton from './TabButton';
import AboutTab from './AboutTab';
import PostsTab from './PostsTab';
import ContactTab from './ContactTab';

export function App() {
  const [isPending, startTransition] = useTransition();
  const [tab, setTab] = useState('about');

  function selectTab(nextTab) {
    startTransition(() => {
      setTab(nextTab);
    });
  }

  return (
    <>
      <TabButton isActive={tab === 'about'} onClick={() => selectTab('about')}>
        About
      </TabButton>
      <TabButton isActive={tab === 'posts'} onClick={() => selectTab('posts')}>
        Posts (slow)
      </TabButton>
      <TabButton
        isActive={tab === 'contact'}
        onClick={() => selectTab('contact')}
      >
        Contact
      </TabButton>
      <hr />
      {tab === 'about' && <AboutTab />}
      {tab === 'posts' && <PostsTab />}
      {tab === 'contact' && <ContactTab />}
    </>
  );
}

 

 

React 18.2์—์„œ๋Š” Transition ํ›…์„ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๋‹ค. React 19์˜ ์ƒˆ๋กœ์šด ์ ์€ ์ด์ œ ๋น„๋™๊ธฐ ๊ธฐ๋Šฅ์„ ์ง€๋‚˜ Transition์„ ์‹œ์ž‘ํ•  ์ˆ˜ ์žˆ์œผ๋ฉฐ, React๋Š” Transition์„ ์‹œ์ž‘ํ•˜๊ธฐ๋ฅผ ๊ธฐ๋‹ค๋ฆฌ๊ณ  ์žˆ๋‹ค.

 

์ด๋Š” AJAX ํ˜ธ์ถœ์„ ํ†ตํ•ด ๋ฐ์ดํ„ฐ๋ฅผ ์ œ์ถœํ•˜๊ณ  ๊ทธ ๊ฒฐ๊ณผ๋ฅผ ํŠธ๋žœ์ง€์…˜์œผ๋กœ ๋ Œ๋”๋งํ•˜๋Š” ๋ฐ ์œ ์šฉํ•˜๋‹ค. ํŠธ๋žœ์ง€์…˜์˜ pending ์ƒํƒœ๋Š” ๋น„๋™๊ธฐ ๋ฐ์ดํ„ฐ ์ œ์ถœ๊ณผ ํ•จ๊ป˜ ์‹œ์ž‘๋œ๋‹ค. ์ด๋Š” ์œ„์—์„œ ์„ค๋ช…ํ•œ ํผ actions ๊ธฐ๋Šฅ์—์„œ ์ด๋ฏธ ์‚ฌ์šฉ๋˜๊ณ  ์žˆ๋‹ค. React๊ฐ€ startTransition์œผ๋กœ ๊ฐ์‹ธ์ง„ <form action> ํ•ธ๋“ค๋Ÿฌ๋ฅผ ํ˜ธ์ถœํ•˜์—ฌ ํ˜„์žฌ ํŽ˜์ด์ง€๋ฅผ ์ฐจ๋‹จํ•˜์ง€ ์•Š๋Š”๋‹ค.

 

 

์ด ๊ธฐ๋Šฅ์€ ์•„์ง React ์„ค๋ช…์„œ์— ๋ฌธ์„œํ™”๋˜์–ด ์žˆ์ง€ ์•Š์ง€๋งŒ pull request์—์„œ ์ด ๊ธฐ๋Šฅ์— ๋Œ€ํ•œ ์ž์„ธํ•œ ๋‚ด์šฉ์„ ์ฝ์„ ์ˆ˜ ์žˆ๋‹ค.

 

๊ฒฐ๋ก 

์ด๋Ÿฌํ•œ ๋ชจ๋“  ๊ธฐ๋Šฅ๋“ค์€ ํด๋ผ์ด์–ธํŠธ ์ „์šฉ์ธ ๋ฆฌ์•กํŠธ ์•ฑ์—์„œ ์ž‘๋™ํ•˜๋ฉฐ, Vite์™€ ํ•จ๊ป˜ ๋ฒˆ๋“ค๋œ ์•ฑ์—์„œ ์ž‘๋™ํ•œ๋‹ค. ๋น„๋ก ์„œ๋ฒ„ ํ†ตํ•ฉํ˜• ๋ฆฌ์•กํŠธ ์•ฑ์—์„œ๋„ ์ด๊ฒƒ์ด ์ž‘๋™ํ•˜์ง€๋งŒ ์ด๊ฒƒ์„ ์‚ฌ์šฉํ•˜๊ธฐ ์œ„ํ•ด Next ํ˜น์€ Remix์™€ ๊ฐ™์€ SSR ํ”„๋ ˆ์ž„์›Œํฌ๋ฅผ ์‚ฌ์šฉํ•  ํ•„์š”๋Š” ์—†๋‹ค. 

 

์ด๋Ÿฌํ•œ ๊ธฐ๋Šฅ์„ ํ†ตํ•ด ๋ฆฌ์•กํŠธ์—์„œ ๋ฐ์ดํ„ฐ ํŒจ์นญ๊ณผ ํผ์„ ๊ตฌํ˜„ํ•˜๊ธฐ๊ฐ€ ํ›จ์”ฌ ์‰ฌ์›Œ์ง„๋‹ค. ํ•˜์ง€๋งŒ ํ›Œ๋ฅญํ•œ ์œ ์ € ๊ฒฝํ—˜์„ ๋งŒ๋“ค๋ ค๋ฉด ์ด ๋ชจ๋“  ํ›…๋ฅผ ํ†ตํ•ฉํ•ด์•ผ ํ•˜๋Š”๋ฐ, ์ด๋Š” ๋ณต์žกํ•  ์ˆ˜ ์žˆ๋‹ค. ๋˜๋Š” ์ตœ์ ์˜ ๋นŒํŠธ์ธ ์—…๋ฐ์ดํŠธ๋ฅผ ์ง€์›ํ•˜๋Š” ์‚ฌ์šฉ์ž ์นœํ™”์ ์ธ ํผ์„ ๊ฐ€์ง„ react-admin๊ณผ ๊ฐ™์€ ํ”„๋ ˆ์ž„์›Œํฌ๋ฅผ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๋‹ค.

 

์ด ๊ธฐ๋Šฅ๋“ค์€ ์™œ React 18.3์ด ์•„๋‹Œ React 19์— ๋„์ž…๋˜๋Š” ๊ฒƒ์ผ๊นŒ? ์ด ๊ธฐ๋Šฅ๋“ค์—๋Š” ์•ฝ๊ฐ„์˜ ๋ณ€๊ฒฝ ์‚ฌํ•ญ์ด ํฌํ•จ๋˜์–ด ์žˆ๊ธฐ ๋•Œ๋ฌธ์— 18.3 release์—๋Š” ์—†์„ ๊ฒƒ์œผ๋กœ ๋ณด์ธ๋‹ค.

 

React 19๋Š” ์–ธ์ œ ์˜ฌ ๊ฒƒ์ธ๊ฐ€ ? ์•„์ง ETA๋Š” ์—†์ง€๋งŒ ์ด ๊ฒŒ์‹œ๋ฌผ์— ์–ธ๊ธ‰๋œ ๋ชจ๋“  ๊ธฐ๋Šฅ์€ ์ด๋ฏธ ์ž‘๋™ํ•˜๊ณ  ์žˆ๋‹ค. ํ•˜์ง€๋งŒ ์•„์ง ์‚ฌ์šฉํ•˜๋Š” ๊ฒƒ์„ ์ถ”์ฒœํ•˜๊ณ  ์‹ถ์ง€๋Š” ์•Š๋‹ค. (Next.js๊ฐ€ ๊ทธ๋ ‡๊ฒŒ ํ•œ๋‹ค๊ณ  ํ•ด๋„) canary release๋ฅผ ํ”„๋กœ๋•ํŠธ์— ์‚ฌ์šฉํ•˜๋Š” ๊ฒƒ์€ ์ข‹์€ ์ƒ๊ฐ์ด ์•„๋‹ˆ๋‹ค.

 

๋ฆฌ์•กํŠธ ์ฝ”์–ด ํŒ€์ด SSR ์•ฑ์—์„œ ์ผํ•˜๋Š” ์‚ฌ๋žŒ๋“ค๋ฟ๋งŒ ์•„๋‹ˆ๋ผ ๋ชจ๋“  ๋ฆฌ์•กํŠธ ๊ฐœ๋ฐœ์ž๋“ค์˜ ๊ฐœ๋ฐœ์ž ๊ฒฝํ—˜์„ ๊ฐœ์„ ํ•˜๊ธฐ ์œ„ํ•ด ๋…ธ๋ ฅํ•˜๊ณ  ์žˆ๋‹ค๋Š” ๊ฒƒ์€ ์ •๋ง ๊ธฐ์œ ์ผ์ด๋‹ค. ๋˜ํ•œ ๊ทธ๋“ค์€ ์ปค๋ฎค๋‹ˆํ‹ฐ ํ”ผ๋“œ๋ฐฑ์— ๊ท€๋ฅผ ๊ธฐ์šธ์ด๊ณ  ์žˆ๋Š” ๊ฒƒ ๊ฐ™๋‹ค - ๋ฐ์ดํ„ฐ ํŒจ์นญ ๋ฐ ํผ ํ•ธ๋“ค๋ง์€ ๋งค์šฐ ํ”ํ•œ ๋ฌธ์ œ์ด๋‹ค.

 

๋‚˜๋Š” React์˜ Stable ๋ฆด๋ฆฌ์ฆˆ์— ์ด ๊ธฐ๋Šฅ๋“ค์ด ๋ณด์ด๊ธธ ๊ธฐ๋Œ€ํ•œ๋‹ค!

 

์›๋ฌธ:  https://dev.to/reenatoteixeira/everything-that-you-need-to-know-about-git-2440

 

 
 
๋‚˜๋Š” ๋‹น์‹ ์ด ๋ณ€๊ฒฝ ์‚ฌํ•ญ์„ ๋˜๋Œ๋ฆฌ๊ณ  ์†์‹ค๋œ ๋ฐ์ดํ„ฐ๋ฅผ ๋ณต๊ตฌํ•  ์ˆ˜ ์žˆ๋„๋ก ์ฝ”๋“œ ๋ฒ„์ „์˜ ์ค‘์š”์„ฑ์„ ์ƒ๊ฐํ•  ๊ฒƒ์ด๋ผ๊ณ  ํ™•์‹ ํ•œ๋‹ค. ์ฐฝ์˜์ ์ธ ์ด๋ฆ„์œผ๋กœ ํŒŒ์ผ ๋ณต์‚ฌ๋ณธ์„ ๋งŒ๋“ค์–ด ๊ฐ€๋ฉฐ ๋ฒ„์ „ ๊ด€๋ฆฌ๋ฅผ ํ•˜๋Š” ๋ˆ„๊ตฐ๊ฐ€(์ €๋Š” ์•„๋‹˜)๋ฅผ ์•Œ ๊ฑฐ๋ผ๊ณ  ์ƒ๊ฐํ•œ๋‹ค..
 

 
์ด๊ฒƒ์€ ์•„๋งˆ๋„ 1972๋…„ ์ด์ „์— ์ฒ˜์Œ์œผ๋กœ ์ค‘์•™ ์ง‘์ค‘์‹ ๋ฒ„์ „ ์ œ์–ด ์†Œํ”„ํŠธ์›จ์–ด ์ค‘ ํ•˜๋‚˜์ธ SCCS(Source Code Control System)๊ฐ€ ์ถœ์‹œ๋˜๋ฉด์„œ ๋ˆ„๊ตฌ๋‚˜ ์ž์‹ ์˜ ์ฝ”๋“œ๋กœ ๋ฒ„์ „ ์ œ์–ด๋ฅผ ํ•  ์ˆ˜ ์žˆ๋Š” ๋ฐฉ๋ฒ•์ด์—ˆ์„ ๊ฒƒ์ด๋‹ค. 
 
๊ทธ๋Ÿฌ๋‚˜ ์šฐ๋ฆฌ๋Š” ์—ฌ๊ธฐ์„œ SCSS๋ฅผ ์–˜๊ธฐํ•˜๋ ค๋Š” ๊ฒƒ์ด ์•„๋‹ˆ๋ผ, ์šฐ๋ฆฌ๊ฐ€ ๊ฐ€์žฅ ๊ด€์‹ฌ์žˆ์–ด ํ•˜๋Š” ๊ฒƒ์€ ๋‚ด๋…„(07/04/2005)์— 20์ฃผ๋…„์„ ๋งž๋Š” ๋ถ„์‚ฐํ˜• ์˜คํ”ˆ์†Œ์Šค ๋ฒ„์ „ ์ œ์–ด ์†Œํ”„ํŠธ์›จ์–ด์ธ GIT์ด๋‹ค. 
 

๋ชฉ์ฐจ

 

1. GIT์ด๋ž€ ๋ฌด์—‡์ธ๊ฐ€?

 

GIT์€ ๋ฆฌ๋ˆ…์Šค ์ปค๋„ ์ œ์ž‘์ž์ธ Linus Torvald์ด ๊ฐœ๋ฐœํ•œ 2005๋…„์— ์ถœ์‹œ๋œ ๋ถ„์‚ฐํ˜• ์˜คํ”ˆ์†Œ์Šค ๋ฒ„์ „ ๊ด€๋ฆฌ ์‹œ์Šคํ…œ์ด๋‹ค. 
 
GIT์„ ํ†ตํ•ด ์šฐ๋ฆฌ๋Š” ํ”„๋กœ์ ํŠธ์˜ ๋ฒ„์ „์„ ์ „์—ญ์ ์œผ๋กœ ๊ด€๋ฆฌํ•  ์ˆ˜ ์žˆ๊ณ (์ž‘์—…ํ•˜๋Š” ํด๋”์—์„œ) ๋ชจ๋“  ๋ณ€๊ฒฝ์‚ฌํ•ญ์„ ๋ฆฌ๋ชจํŠธ ๋ ˆํฌ์ง€ํ† ๋ฆฌ์™€ ์‹ฑํฌ๋ฅผ ๋งž์ถœ ์ˆ˜ ์žˆ๋‹ค(์˜ˆ๋ฅผ ๋“ค์–ด GitHub์—์„œ). 

 



 

2. GIT์€ ์–ด๋–ป๊ฒŒ  ์ž‘๋™ํ• ๊นŒ?

 

๋ชจ๋“  ํ”„๋กœ์ ํŠธ ํŒŒ์ผ์ด ์žˆ๋Š” ํด๋”๊ฐ€ ์žˆ๋Š” ๋ฌผ๋ฆฌ์ ์ธ ํŒŒ์ผ ์บ๋น„๋‹›์„ ์ƒ์ƒํ•ด๋ณด๋ผ. ๋ˆ„๊ตฐ๊ฐ€ ํŒŒ์ผ์„ ์กฐ์ž‘ํ•˜๋ ค๊ณ  ํ•  ๋•Œ๋งˆ๋‹ค, ๊ทธ๋“ค์€ ๊ทธ๊ฒƒ์„ ๊ณจ๋ผ์•ผ ํ•˜๊ณ  ํด๋”์—์„œ ๊ทธ๊ฒƒ์„ ์ง€์šฐ๊ณ  ๋๋‚œ ํ›„์—๋Š” ๋‹ค์‹œ ํด๋”์— ๋˜๋Œ๋ ค ๋†“์•„์•ผ ํ•œ๋‹ค. ๋”ฐ๋ผ์„œ ๋‘ ์‚ฌ๋žŒ์ด ๋™์ผํ•œ ํŒŒ์ผ์„ ์ž‘์—…ํ•˜๋Š” ๊ฒƒ์€ ๋ถˆ๊ฐ€๋Šฅํ•˜์—ฌ ๋ฐœ์ƒ ๊ฐ€๋Šฅํ•œ ์ถฉ๋Œ์„ ์™„์ „ํžˆ ํ”ผํ•  ์ˆ˜ ์žˆ๋‹ค.
 

๊ทธ๋Ÿฌ๋‚˜ ์ด๊ฒƒ์ด GIT์ด ์ž‘๋™ํ•˜๋Š” ๋ฐฉ์‹์€ ์•„๋‹ˆ๋‹ค! (thanks God)

 

์ด๊ฒƒ์€ ์ค‘์•™ ์ง‘์ค‘๋œ ๋ฒ„์ „ ์ปจํŠธ๋กค ์‹œ์Šคํ…œ์ด ์ž‘๋™๋˜๋Š” ๋ฐฉ์‹์œผ๋กœ, ์‚ฌ์šฉ์ž๋Š” ํŒŒ์ผ์„ 'check-out(์ฒดํฌ์•„์›ƒ)'ํ•˜๊ณ  'check-in(์ฒดํฌ์ธ)'ํ•ด์•ผ ํ•œ๋‹ค. ํŠน์ • ํŒŒ์ผ์— ๋Œ€ํ•œ ์ž‘์—…์ด ํ•„์š”ํ•  ๋•Œ๋งˆ๋‹ค ํ•ด๋‹น ํŒŒ์ผ์„ ์ฒดํฌ์•„์›ƒํ•˜์—ฌ ์ €์žฅ์†Œ์—์„œ ์ œ๊ฑฐํ•œ ๋‹ค์Œ ์ž‘์—…์ด ์™„๋ฃŒ๋˜๋ฉด ํŒŒ์ผ์„ ์ฒดํฌ์ธํ•˜์—ฌ ์ €์žฅ์†Œ๋กœ ๋ฐ˜ํ™˜ํ•ด์•ผ ํ•œ๋‹ค.


 
GIT๊ฐ™์€ ๋ถ„์‚ฐํ˜• ์‹œ์Šคํ…œ์—์„œ๋Š” ๊ฐ™์€ ๋ ˆํฌ์ง€ํ† ๋ฆฌ์˜ ํŒŒ์ผ์— ์—ฌ๋Ÿฌ ์‚ฌ๋žŒ๋“ค์ด ๋™์‹œ์— ํŒŒ์ผ์— ์ ‘๊ทผํ•˜๋Š” ๊ฒƒ์ด ๊ฐ€๋Šฅํ•˜๋‹ค. ๋ˆ„๊ตฐ๊ฐ€ ํŒŒ์ผ์„ ์กฐ์ž‘ํ•  ๋•Œ๋งˆ๋‹ค ํŒŒ์ผ์„ ๋กœ์ปฌ๋กœ ๋ณต์ œ(๋˜๋Š” ์ „์ฒด ๋ ˆํฌ์ง€ํ† ๋ฆฌ๋ฅผ ๋ณต์ œ)ํ•œ ๋‹ค์Œ ์ˆ˜์ •์‚ฌํ•ญ์„ ์›๊ฒฉ ๋ ˆํฌ์ง€ํ† ๋ฆฌ๋กœ ๋‹ค์‹œ ๋ณด๋‚ผ ์ˆ˜ ์žˆ๋‹ค. ์ด๋ฅผ ํ†ตํ•ด ์—ฌ๋Ÿฌ ์‚ฌ๋žŒ์ด ๋™์ผํ•œ ํŒŒ์ผ์„ ์กฐ์ž‘ํ•˜๋ฉด์„œ ๋™์ผํ•œ ํ”„๋กœ์ ํŠธ์—์„œ ์ž‘์—…ํ•  ์ˆ˜ ์žˆ๋‹ค.


์ด๊ฒƒ์€ ์„ธ๊ณ„ ์—ฌ๋Ÿฌ ์ง€์—ญ์˜ ์‚ฌ๋žŒ๋“ค์ด ๊ฐ™์€ ํ”„๋กœ์ ํŠธ์—์„œ ์ž‘์—…ํ•˜๊ณ  ์ˆ˜์ • ๋ฐ ๋ฐœ์ƒ ๊ฐ€๋Šฅํ•œ ์ถฉ๋Œ์„ ๊ด€๋ฆฌํ•˜๋Š” ๋Œ€๊ทœ๋ชจ ์˜คํ”ˆ ์†Œ์Šค ํ”„๋กœ์ ํŠธ์˜ ๋ฐฐํฌ๋ฅผ ํ—ˆ์šฉํ•œ๋‹ค(์—ฌ๊ธฐ์„œ ๋ณ‘ํ•ฉ ์ถฉ๋Œ(merge conflicts)์ด ๋ฐœ์ƒํ•  ์ˆ˜ ์žˆ๋‹ค).


3. GIT ์„ค์น˜ํ•˜๊ธฐ


GIT์€ ๋งค์šฐ ๊ฐ„๋‹จํ•œ ์„ค์น˜ ํ”„๋กœ์„ธ์Šค๋ฅผ ํ†ตํ•ด ์ฃผ์š” ์šด์˜ ์ฒด์ œ(Windows, Linux, MacOs...)์—์„œ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ์œผ๋ฉฐ, ์ด๋Š” ๋ช…๋ น์ค„์ด๋‚˜ git-scm.com ์˜ ๊ณต์‹ ์„ค์น˜ ํ”„๋กœ๊ทธ๋žจ์„ ํ†ตํ•ด ์„ค์น˜๊ฐ€ ๊ฐ€๋Šฅํ•˜๋‹ค.

3.1 ์œˆ๋„์šฐ์—์„œ ์„ค์น˜ํ•˜๊ธฐ


์œˆ๋„์šฐ์— GIT๋ฅผ ์„ค์น˜ํ•˜๋ ค๋ฉด ๊ณต์‹ ์›น์‚ฌ์ดํŠธ์— ๋“ค์–ด๊ฐ€์„œ ์„ค์น˜ ํ”„๋กœ๊ทธ๋žจ์„ ๋‹ค์šด๋กœ๋“œํ•˜๊ธฐ๋งŒ ํ•˜๋ฉด ๋œ๋‹ค. ๊ทธ๋ฆฌ๊ณ  ๋‚˜์„œ ์ง€์‹œ์‚ฌํ•ญ์„ ๋”ฐ๋ผ๊ฐ€๋ฉด ๋ชจ๋“  ๊ฒƒ์ด ์ž˜ ๋  ๊ฒƒ์ด๋‹ค. ๊ทธ๋ฆฌ๊ณ  ์šฐ๋ฆฌ๋Š” ํ„ฐ๋ฏธ๋„์—์„œ GIT ๋ช…๋ น์„ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ์„ ๊ฒƒ์ด๋‹ค.

3.2 ๋ฆฌ๋ˆ…์Šค์—์„œ ์„ค์น˜ํ•˜๊ธฐ


๋ฆฌ๋ˆ…์Šค์˜ ๊ฒฝ์šฐ๋Š” ์•„๋ž˜ ๋ช…๋ น์„ ์‚ฌ์šฉํ•ด GIT๋ฅผ ์„ค์น˜ํ•  ์ˆ˜ ์žˆ๋‹ค:

sudo apt install git-all


์ด ๋ช…๋ น์–ด๋ฅผ ํ†ตํ•ด GIT์ด ์šฐ๋ฆฌ์˜ ํ„ฐ๋ฏธ๋„์—์„œ ์‹คํ–‰๋  ์ค€๋น„๋ฅผ ํ•ด์•ผ ํ•œ๋‹ค.

3.3 Mac์—์„œ ์„ค์น˜ํ•˜๊ธฐ


Mac์˜ ๊ฒฝ์šฐ GIT๋ฅผ ์„ค์น˜ํ•˜๋Š” ๊ฐ€์žฅ ์‰ฌ์šด ๋ฐฉ๋ฒ•์€ Homebrew๋ฅผ ์„ค์น˜ํ•œ ๋‹ค์Œ ํ„ฐ๋ฏธ๋„์—์„œ ์•„๋ž˜ ๋ช…๋ น์„ ์‹คํ–‰ํ•˜๋Š” ๊ฒƒ์ด๋‹ค:
 

brew install git

 
์ด ๋ช…๋ น์–ด๋ฅผ ํ†ตํ•ด GIT์ด ์šฐ๋ฆฌ์˜ ํ„ฐ๋ฏธ๋„์—์„œ ์‹คํ–‰๋  ์ค€๋น„๋ฅผ ํ•ด์•ผ ํ•œ๋‹ค.


4. GIT ๊ตฌ์„ฑํ•˜๊ธฐ

 
์„ค์น˜ํ•œ ํ›„์—๋Š” ์•„๋ž˜ ์‹คํ–‰์„ ํ†ตํ•ด GIT์„ ๊ตฌ์„ฑํ•˜๋Š” ๊ฒƒ์ด ์ค‘์š”ํ•˜๋‹ค:

git config --global user.name "[username]"
# e.g. John Doe
git config --global user. email "[email@email.com]"
# e.g. johndoe@email.com


 

๋˜ํ•œ --global ํƒœ๊ทธ๋ฅผ ์ œ๊ฑฐํ•˜์—ฌ ํŠน์ • ๋กœ์ปฌ ๋ฆฌํฌ์ง€ํ† ๋ฆฌ์— ๋Œ€ํ•œ ํŠน์ • ์‚ฌ์šฉ์ž๋ฅผ ๊ตฌ์„ฑํ•  ์ˆ˜๋„ ์žˆ๋‹ค.

 


 5. ๋กœ์ปฌ ๋ ˆํฌ์ง€ํ† ๋ฆฌ ์‹œ์ž‘ํ•˜๊ธฐ

 
GIT์ด ๊ตฌ์„ฑ๋˜๋ฉด ๋กœ์ปฌ ์ €์žฅ์†Œ๋ฅผ ์‹œ์ž‘ํ•  ์ˆ˜ ์žˆ๋‹ค. ์ด๋ฅผ ์œ„ํ•ด ์ƒˆ ์ €์žฅ์†Œ๋ฅผ ์ฒ˜์Œ๋ถ€ํ„ฐ ์‹œ์ž‘ํ•˜๊ฑฐ๋‚˜ ๊ธฐ์กด ์›๊ฒฉ ์ €์žฅ์†Œ๋ฅผ ๋ณต์ œํ•  ์ˆ˜ ์žˆ๋‹ค.

5.1 ์ฒ˜์Œ๋ถ€ํ„ฐ ์‹œ์ž‘ํ•˜๊ธฐ(git init)


์ƒˆ ๋ ˆํฌ์ง€ํ† ๋ฆฌ๋ฅผ ์‹œ์ž‘ํ•˜๋ ค๋ฉด ์›ํ•˜๋Š” ๋ ˆํฌ์ง€ํ† ๋ฆฌ ๋ฃจํŠธ ํด๋”๋กœ ์ด๋™ํ•˜๊ณ  ์•„๋ž˜ ๋ช…๋ น์„ ์‹คํ–‰ํ•˜๊ธฐ๋งŒ ํ•˜๋ฉด ๋œ๋‹ค.

git init

 

 

์ด๋ฅผ ํ†ตํ•ด ํ”„๋กœ์ ํŠธ ํด๋”์—  .git ๋””๋ ‰ํ† ๋ฆฌ๊ฐ€ ์ƒ์„ฑ๋˜๋ฉฐ, ์ด ๋””๋ ‰ํ† ๋ฆฌ๋Š” ๋กœ์ปฌ ์ €์žฅ์†Œ์˜ ์ž‘์—… ํด๋”์˜ ๋ฒ„์ „ ์ปจํŠธ๋กค์„ ๋‹ด๋‹นํ•œ๋‹ค. 

 

5.2 ๊ธฐ์กด ๋ ˆํฌ์ง€ํ† ๋ฆฌ ๋ณต์ œํ•˜๊ธฐ(git clone)

๊ธฐ์กด ์›๊ฒฉ ์ €์žฅ์†Œ๋ฅผ ๋ณต์ œํ•˜๋Š” ๊ฒƒ์€ ์ƒˆ ์ €์žฅ์†Œ๋ฅผ ์ฒ˜์Œ๋ถ€ํ„ฐ ์‹œ์ž‘ํ•˜๋Š” ๊ฒƒ๋งŒํผ ์‰ฝ๋‹ค. ์ด๋ฅผ ์œ„ํ•ด ์šฐ๋ฆฌ๋Š” ๋ ˆํฌ์ง€ํ† ๋ฆฌ๋ฅผ ๋‹ค์šด๋กœ๋“œ ํ•˜๊ณ  ์‹ถ์€ ๊ณณ์— ๋ฆฌ๋ชจํŠธ ์ €์žฅ์†Œ์˜ URL๊ณผ ํ•จ๊ป˜ git clone ๋ช…๋ น์–ด๋ฅผ ์‚ฌ์šฉํ•œ๋‹ค.

 

git clone [repository-url]

 

 

๊ทธ๋ฆฌ๊ณ  ๋‚˜๋ฉด ์ „์ฒด ๋ ˆํฌ์ง€ํ† ๋ฆฌ๊ฐ€ ์šฐ๋ฆฌ์˜ ๋กœ์ปฌ ์ €์žฅ์†Œ์— ๋ณต์ œ๋  ๊ฒƒ์ด๊ณ  ์ž๋™์œผ๋กœ ์—ฐ๊ด€๋œ ์›๊ฒฝ ์ €์žฅ์†Œ์™€ ์—ฐ๊ฒฐ๋  ๊ฒƒ์ด๋‹ค.

 

๋ ˆํฌ์ง€ํ† ๋ฆฌ ๋ณต์ œ๋Š” ์šฐ๋ฆฌ๊ฐ€ ๋”์ด์ƒ git remote ๋ช…๋ น์–ด๋ฅผ ๋ฏธ๋ž˜์— ์‚ฌ์šฉํ•  ํ•„์š”๊ฐ€ ์—†๋‹ค๋Š” ๊ฒƒ์„ ๋œปํ•œ๋‹ค.

 


 

6. GIT์œผ๋กœ ์ž‘์—…ํ•˜๊ธฐ

์šฐ๋ฆฌ์˜ ๋กœ์ปฌ ์ €์žฅ์†Œ์—์„œ ์šฐ๋ฆฌ๋Š” ์šฐ๋ฆฌ ํ”„๋กœ์ ํŠธ์— ํ•„์š”ํ•œ ํŒŒ์ผ์„ ๋งŒ๋“ค ์ˆ˜ ์žˆ์ง€๋งŒ ๊ทธ ํŒŒ์ผ๋“ค์ด ์ž๋™์œผ๋กœ GIT์— ์˜ํ•ด ๋™๊ธฐํ™”๋˜์ง€๋Š” ์•Š์„ ๊ฒƒ์ด๋‹ค. ์šฐ๋ฆฌ๋Š” ๋ฒ„์ „ ๋ณ€๊ฒฝ ์‚ฌํ•ญ์ด ์ƒ๊ธธ ๊ฒฝ์šฐ GIT์— ๋ณด๊ณ ํ•ด์•ผ ํ•œ๋‹ค.

 

๊ทธ๋Ÿฌ๋ฏ€๋กœ ์šฐ๋ฆฌ๋Š” ์šฐ๋ฆฌ๊ฐ€ ์›ํ•˜๋Š” ๋Œ€๋กœ ํŒŒ์ผ์„ ์กฐ์ž‘ํ•˜๊ณ  ๋ณ€๊ฒฝ ์‚ฌํ•ญ์„ ์ˆ˜์ •ํ•œ ํ›„์—๋Š” ๊นƒ์— ์ˆ˜์ •๋œ ํŒŒ์ผ์„ ๋ณด๋‚ธ๋‹ค.

 

์ด๋ฅผ ์œ„ํ•ด ๋ฒ„์ „ ์ปจํŠธ๋กค์— 3๋‹จ๊ณ„์˜ ๋ฌดํ•œ ํ”Œ๋กœ์šฐ๊ฐ€ ์žˆ๋‹ค๋Š” ๊ฒƒ์„ ์ดํ•ดํ•˜๋Š” ๊ฒƒ์ด ์ค‘์š”ํ•˜๋‹ค.

 

 MODIFY -> STAGE -> COMMIT

 

 

  • MODIFY(์ˆ˜์ • ๋‹จ๊ณ„): ๋ฒ„์ „ ์ปจํŠธ๋กค์˜ ์ฒซ ๋ฒˆ์งธ ์ž‘์—…์€ MODIFY์ด๋‹ค. ์—ฌ๊ธฐ์„œ๋Š” ์‚ฌ์šฉ ๊ฐ€๋Šฅํ•œ ๋งˆ์ง€๋ง‰ ๋ฒ„์ „๊ณผ ๋น„๊ตํ•˜์—ฌ ๋ณ€๊ฒฝ๋œ ํŒŒ์ผ์„ ์ฐพ๋Š”๋‹ค.
  • STAGE(์Šคํ…Œ์ด์ง€ ๋‹จ๊ณ„): ๋‘ ๋ฒˆ์งธ stage ๋‹จ๊ณ„์—์„œ๋Š” ์šฐ๋ฆฌ๊ฐ€ ๋‹ค์Œ ์ปค๋ฐ‹์— ์ถ”๊ฐ€ํ•˜๊ณ  ์‹ถ์€ ํŒŒ์ผ์„ ์ˆ˜์ •๋œ ํŒŒ์ผ์— ์œ„์น˜ ์‹œํ‚จ๋‹ค.
  • COMMIT(์ปค๋ฐ‹ ๋‹จ๊ณ„): ๋งˆ์ง€๋ง‰ ๋‹จ๊ณ„์ธ commit ๋‹จ๊ณ„์—์„œ๋Š” ์šฐ๋ฆฌ๊ฐ€ ๋ณ€๊ฒฝ ์‚ฌํ•ญ์„ ํ™•์ธํ•  ๋•Œ ์Šคํ…Œ์ด์ง€์˜ ์ˆ˜์ •๋œ ํŒŒ์ผ์„ ๋กœ์ปฌ ์ €์žฅ์†Œ์— ๋ณด๋‚ธ๋‹ค.

 

์ˆ˜์ •๋œ ํŒŒ์ผ๋“ค์„ ์ปค๋ฐ‹ํ•œ ํ›„์—๋Š” ๋กœ์ปฌ ์ €์žฅ์†Œ์—์„œ ์ƒˆ๋กœ์šด ๋ฒ„์ „์„ ๊ฐ€์ง€๊ฒŒ ๋˜๋ฉฐ, ๋‹ค์‹œ ์—…๋ฐ์ดํŠธ ์‚ฌํ•ญ๋“ค์„ ๋ฐ›๊ณ  ํ•œ ๋ฒˆ ๋” '์ˆ˜์ •'ํ•˜๊ณ  '์Šคํ…Œ์ด์ง€'์— ์œ„์น˜์‹œํ‚ค๊ณ  ๋‹ค์‹œ '์ปค๋ฐ‹'ํ•  ์ˆ˜ ์žˆ์œผ๋ฉฐ ์ƒˆ๋กœ์šด ๋ฒ„์ „์„ ํ™•์ธํ•˜๋Š” ๋“ฑ์˜ ์ž‘์—…์„ ์ˆ˜ํ–‰ํ•  ์ˆ˜ ์žˆ๋‹ค. (๊ทธ๋ž˜์„œ '๋ฌดํ•œ' ํ”Œ๋กœ์šฐ๋ผ๊ณ  ํ•œ ๊ฒƒ ใ…Žใ…Ž)

 

์ปค๋ฐ‹์€ ์ˆ˜์ •๋œ ํŒŒ์ผ์˜ ์ด์ „ ๋ฒ„์ „์„ ๋ฎ์–ด์“ฐ์ง€ ์•Š์œผ๋ฉฐ, ๋งˆ์ง€๋ง‰ ๋ฒ„์ „์— ๋Œ€ํ•œ ํฌ์ธํ„ฐ๊ฐ€ ์žˆ๋Š” ์ƒˆ ๋ฒ„์ „์„ ํฌํ•จํ•˜๋ฏ€๋กœ GIT์— ์˜ํ•ด ํŠธ๋ž˜ํ‚น๋˜๋Š” ๊ฐ ํŒŒ์ผ์˜ ๋ฒ„์ „์„ ์ถ”์ ํ•˜๋Š” ๊ฒƒ์ด ์ค‘์š”ํ•˜๋‹ค.

 

6.1 ์ถ”๊ฐ€ํ•˜๊ณ  ์ปค๋ฐ‹ํ•˜๊ธฐ(git add์™€ git commit)

๋ณต์žกํ•˜๊ฒŒ ๋“ค๋ฆด์ง€ ๋ชจ๋ฅด์ง€๋งŒ, ๋ฒ„์ „ ์ œ์–ด ํ๋ฆ„์„ ์ˆ˜ํ–‰ํ•˜๋Š” ๊ฒƒ์€ ๋งค์šฐ ๊ฐ„๋‹จํ•˜๋‹ค๋‹ค. ์›ํ•˜๋Š” ์ˆ˜์ •์ด ์™„๋ฃŒ๋˜์—ˆ์œผ๋ฏ€๋กœ, ์šฐ๋ฆฌ๋Š” ์•„๋ž˜ ๋ช…๋ น์œผ๋กœ ์ปค๋ฐ‹ํ•˜๊ณ ์ž ํ•˜๋Š” ๋‹จ๊ณ„์— ์ˆ˜์ •๋œ ํŒŒ์ผ์„ ์ถ”๊ฐ€ํ•œ๋‹ค:

git add [filename]

 

git add -A : ๋ชจ๋“  ์ˆ˜์ •๋œ ํŒŒ์ผ์„ ์Šคํ…Œ์ด์ง€์— ํ•œ ๋ฒˆ์— ์ถ”๊ฐ€
git add *. [extensão-do-arquivo] : ํŠน์ • ์ต์Šคํ…์…˜ ํŒŒ์ผ์˜ ์ˆ˜์ •๋œ ํŒŒ์ผ์„ ์Šคํ…Œ์ด์ง€์— ํ•œ ๋ฒˆ์— ์ถ”๊ฐ€ (git add *.html ๊ณผ ๊ฐ™์ด)

 

 

์šฐ๋ฆฌ๋Š” git status ๋ช…๋ น์„ ์‚ฌ์šฉํ•˜์—ฌ ์–ธ์ œ๋“ ์ง€ ํ˜„์žฌ ๋กœ์ปฌ ์ €์žฅ์†Œ ์ƒํƒœ๋ฅผ ํ™•์ธํ•  ์ˆ˜ ์žˆ๋‹ค:

 

 

์ƒˆ ํŒŒ์ผ์„ ๋งŒ๋“  ํ›„ ์ €์žฅ์†Œ ๋‚ด์—์„œ git status๋ฅผ ์‹คํ–‰ํ•˜๋ฉด ์ƒˆ ํŒŒ์ผ์ด "Untracked(์ถ”์ ๋˜์ง€ ์•Š์Œ)"์œผ๋กœ ํ‘œ์‹œ๋œ๋‹ค. ์ฆ‰, ์ด ํŒŒ์ผ์€ ์ƒˆ๋กœ์šด ๊ฒƒ์ด๋ฉฐ GIT์— ์˜ํ•ด ์ถ”์ ๋˜๊ธฐ ์œ„ํ•ด์„œ๋Š” ์–ด๋–ค ์ปค๋ฐ‹์—๋ผ๋„ ์ถ”๊ฐ€๋˜์–ด์•ผ ํ•œ๋‹ค๋Š” ๊ฒƒ์„ ์˜๋ฏธํ•œ๋‹ค.

 

GIT๊ฐ€ ์ €์žฅ์†Œ ๋‚ด์˜ ํŠน์ • ํŒŒ์ผ์ด๋‚˜ ํด๋”๋ฅผ ๋ฌด์‹œํ•˜๋„๋ก ํ•  ์ˆ˜ ์žˆ๋‹ค. ์ด๋ฅผ ์œ„ํ•ด์„œ๋Š” ๋ฃจํŠธ ํด๋”์— .gitignore๋ผ๋Š” ํŒŒ์ผ์„ ์ถ”๊ฐ€ํ•˜๊ณ , ๊ทธ ์•ˆ์—์„œ ๋ฌด์‹œํ•ด์•ผ ํ•  ํŒŒ์ผ์ด๋‚˜ ํด๋”์˜ ์ด๋ฆ„์„ ์ ์œผ๋ฉด ๋œ๋‹ค.

์ฃผ์˜: ๋ฌด์‹œ๋œ ํŒŒ์ผ๊ณผ ํด๋”๋Š” ๋” ์ด์ƒ GIT ํŠธ๋ž™์— ๋‚˜ํƒ€๋‚˜์ง€ ์•Š์œผ๋ฉฐ, ์‹ฌ์ง€์–ด "Untracked"๋กœ๋„ ํ‘œ์‹œ๋˜์ง€ ์•Š๋Š”๋‹ค. ์ถ”์ ์„ ์žฌ์„ค์ •ํ•˜๋ ค๋ฉด .gitignore ํŒŒ์ผ์—์„œ ์›ํ•˜๋Š” ์ด๋ฆ„์„ ์‚ญ์ œํ•˜๊ธฐ๋งŒ ํ•˜๋ฉด ๋œ๋‹ค.

 

 

ํŒŒ์ผ์„ ํฌํ•จํ•˜๊ธฐ ์œ„ํ•ด git add ๋ช…๋ น์„ ์ถ”๊ฐ€ํ•  ํŒŒ์ผ์˜ ์ด๋ฆ„("index.html")์œผ๋กœ ์‹คํ–‰ํ•  ์ˆ˜ ์žˆ๋‹ค:

 

 

 

์ด๋Ÿฌํ•œ ๋ฐฉ์‹์œผ๋กœ git status ๋‹ค์‹œ ์‹คํ–‰ํ•˜๋ฉด ์ƒˆ ํŒŒ์ผ์ด "stage"์— ์ถ”๊ฐ€๋˜์—ˆ์œผ๋ฉฐ ์ตœ์ข…์ ์œผ๋กœ ๋‹ค์Œ ์ปค๋ฐ‹์—์„œ ๋ณด๋‚ผ ์ค€๋น„๊ฐ€ ๋˜์—ˆ์Œ์„ ์•Œ ์ˆ˜ ์žˆ๊ณ , ์ด๋Š” ์•„๋ž˜ ๋ช…๋ น์„ ํ†ตํ•ด ์ˆ˜ํ–‰ํ•  ์ˆ˜ ์žˆ๋‹ค:

 

git commit -m "[descriptive-message]"

 

์ปค๋ฐ‹์€ ๊ณ ์œ  ID(ํ•ด์‹œ ์ฝ”๋“œ)๋ฅผ ๊ฐ€์ง€๋ฉฐ, ๋ณ€๊ฒฝํ•  ์ˆ˜ ์—†๋‹ค. ์ฆ‰, ์ปค๋ฐ‹์€ ํ™•์ธ๋˜๋ฉด ์ˆ˜์ •ํ•  ์ˆ˜ ์—†๋‹ค.

git commit -a: ์ง์ ‘ ์ปค๋ฐ‹์„ ์ˆ˜ํ–‰ํ•˜๋ฉฐ ๋ชจ๋“  ์ˆ˜์ •๋œ ํŒŒ์ผ์„ ์Šคํ…Œ์ด์ง€์— ์ถ”๊ฐ€ํ•˜๊ณ  ์ปค๋ฐ‹ํ•œ๋‹ค.

 

ํŒŒ์ผ์„ ์„ฑ๊ณต์ ์œผ๋กœ ์ปค๋ฐ‹ํ•œ ํ›„ git status๋ฅผ ์‹คํ–‰ํ•  ๋•Œ ๋งˆ์ง€๋ง‰ ์ปค๋ฐ‹์„ ํ†ตํ•ด ๋ชจ๋“  ์ˆ˜์ • ์‚ฌํ•ญ์ด ๋กœ์ปฌ ์ €์žฅ์†Œ์— ํšจ๊ณผ์ ์œผ๋กœ ์ €์žฅ๋˜์—ˆ๊ธฐ ๋•Œ๋ฌธ์— ๋” ์ด์ƒ ์—…๋กœ๋“œํ•  ์ˆ˜์ •๋œ ํŒŒ์ผ์ด ์—†์Œ์„ ์•Œ ์ˆ˜ ์žˆ๋‹ค.

 

 

๋˜ํ•œ ํ•ด์‹œ ์ฝ”๋“œ, ๋ธŒ๋žœ์น˜, ์ž‘์„ฑ์ž, ๋‚ ์งœ ๋“ฑ ๋ชจ๋“  ์ปค๋ฐ‹์˜ ์ผ๋ถ€ ๋ฉ”ํƒ€๋ฐ์ดํ„ฐ๋ฅผ ๋ณด์—ฌ์ฃผ๋Š” git log ๋ช…๋ น์„ ์‚ฌ์šฉํ•ด ์ €์žฅ์†Œ์˜ ์ปค๋ฐ‹ ๋กœ๊ทธ๋ฅผ ๊ฒ€ํ† ํ•ด ๋ณ€๊ฒฝํ•œ ๋‚ด์šฉ์„ ํ™•์ธํ•  ์ˆ˜ ์žˆ๋‹ค.

 

 

 

์ด ๋ชจ๋“  ๊ณผ์ •์„ ๋ฐ˜๋ณตํ•˜์—ฌ ํ”„๋กœ์ ํŠธ์— ํ•„์š”ํ•œ ์ƒˆ ํŒŒ์ผ์„ ์ถ”๊ฐ€ํ•˜๊ณ  ์ˆ˜์ •ํ•œ ํ›„ ์ƒˆ๋กœ์šด ์ปค๋ฐ‹์„ ๋งŒ๋“ค์–ด ๋กœ์ปฌ ์ €์žฅ์†Œ๋กœ ๋ณด๋‚ผ ์ˆ˜ ์žˆ๋‹ค.

 

 

git log -N : ๋งˆ์ง€๋ง‰ N๊ฐœ์˜ ์ปค๋ฐ‹์ด ํฌํ•จ๋œ log๋ฅผ ๋ณด์—ฌ์ค€๋‹ค.
git log [branch-A] [branch-B]: "branch-B"์—๋Š” ์žˆ์ง€๋งŒ "A"์—๋Š” ์—†๋Š” ์ปค๋ฐ‹ ๋กœ๊ทธ๋ฅผ ํ‘œ์‹œํ•œ๋‹ค.
git log --follow [filename]: ํŒŒ์ผ์˜ ์ด๋ฆ„์„ ๋ณ€๊ฒฝํ•œ ๊ฒฝ์šฐ์—๋„ ์ง€์ •ํ•œ ํŒŒ์ผ์„ ๋ณ€๊ฒฝํ•œ ์ปค๋ฐ‹ ๋กœ๊ทธ๋ฅผ ํ‘œ์‹œํ•œ๋‹ค.
git diff: ์ €์žฅ์†Œ์—์„œ ์‚ฌ์šฉ ๊ฐ€๋Šฅํ•œ ์ตœ์‹  ๋ฒ„์ „๊ณผ ๋น„๊ตํ•˜์—ฌ ๋ณ€๊ฒฝํ•œ ๋‚ด์šฉ์„ ๋‚˜์—ดํ•œ๋‹ค.
git diff [nome-do-arquivo]: ์ €์žฅ์†Œ์—์„œ ๋งˆ์ง€๋ง‰์œผ๋กœ ์‚ฌ์šฉ ๊ฐ€๋Šฅํ•œ ๋ฒ„์ „๊ณผ ๊ด€๋ จํ•˜์—ฌ ์ง€์ •๋œ ํŒŒ์ผ์— ๋Œ€ํ•ด ์ˆ˜ํ–‰ํ•œ ๋ณ€๊ฒฝ ์‚ฌํ•ญ์„ ๋‚˜์—ดํ•œ๋‹ค.

 

6.2 ์ปค๋ฐ‹ ์ „๊ณผ ํ›„์—์„œ ๋ณ€๊ฒฝ ์‚ฌํ•ญ ์ทจ์†Œํ•˜๊ธฐ

์ปค๋ฐ‹์ด ์ด๋ฃจ์–ด์ง€๊ธฐ ์ „์— ๋กœ์ปฌ ์ €์žฅ์†Œ์—์„œ ์ด๋ฃจ์–ด์ง„ ๋ชจ๋“  ๋ณ€๊ฒฝ์€ ์ทจ์†Œํ•˜๊ฑฐ๋‚˜ ๋ณ€๊ฒฝํ•  ์ˆ˜ ์žˆ์ง€๋งŒ, ์ปค๋ฐ‹์ด ํ•œ ๋ฒˆ ์ด๋ฃจ์–ด์ง€๋ฉด ๋ณ€๊ฒฝํ•  ์ˆ˜ ์—†๋‹ค. ์ปค๋ฐ‹์€ ๋ถˆ๋ณ€์˜ ๊ฐ์ฒด์ด๊ธฐ ๋•Œ๋ฌธ์— ์ปค๋ฐ‹์—์„œ ๋ฐ์ดํ„ฐ๋ฅผ ํŽธ์ง‘ํ•˜๊ฑฐ๋‚˜ ๋ณ€๊ฒฝํ•˜๋Š” ๊ฒƒ์€ ๋ถˆ๊ฐ€๋Šฅํ•˜๋‹ค.

 

๊ทธ๋Ÿฌ๋‚˜ ๋ณ€๊ฒฝ์„ ์ทจ์†Œํ•˜๋Š” ์ƒˆ๋กœ์šด ์ปค๋ฐ‹์„ ๋งŒ๋“ค๊ฑฐ๋‚˜ ์ด์ „ ์ปค๋ฐ‹์—์„œ ์ž˜๋ชป๋œ ์ •๋ณด๋ฅผ ์ˆ˜์ •ํ•  ์ˆ˜ ์žˆ๋‹ค. ์–ด๋Š ์ชฝ์ด๋“  ์šฐ๋ฆฌ๋Š” ๋‹ค์Œ ๋ช…๋ น ์ค‘ ํ•˜๋‚˜๋ฅผ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๋‹ค:

 

git checkout -- [filename]
# ์ปค๋ฐ‹ ์ „์— ๋กœ์ปฌ ํŒŒ์ผ์— ๋Œ€ํ•œ ๋ณ€๊ฒฝ ์‚ฌํ•ญ์„ ํ๊ธฐ(๋Œ์ดํ‚ฌ ์ˆ˜ ์—†๋Š” ์ž‘์—…)

 

git reset --hard HEAD
# ์Šคํ…Œ์ด์ง€ ๋‹จ๊ณ„(์ปค๋ฐ‹ ์ „)์— ์žˆ๋Š” ํŒŒ์ผ์˜ ๋ณ€๊ฒฝ ๋‚ด์šฉ์„ ํ๊ธฐ

 

git reset --hard HEAD~1
# ๋กœ์ปฌ ๋ฆฌํฌ์ง€ํ† ๋ฆฌ์—์„œ ์ˆ˜ํ–‰ํ•œ ๋งˆ์ง€๋ง‰ ์ปค๋ฐ‹์„ ํ๊ธฐ(๋งˆ์ง€๋ง‰ ์ปค๋ฐ‹๋งŒ ํ•ด๋‹น)

 

git commit --amend
# ๋กœ์ปฌ ์ €์žฅ์†Œ์—์„œ ์ˆ˜ํ–‰ํ•œ ๋งˆ์ง€๋ง‰ ์ปค๋ฐ‹์„ ๋Œ€์ฒดํ•˜์—ฌ ์ƒˆ ์ปค๋ฐ‹์„ ์ž‘์„ฑ

 

git revert [commit-hash]
# ์ง€์ •ํ•œ ์ปค๋ฐ‹์˜ ๋ณ€๊ฒฝ์‚ฌํ•ญ์„ ๋˜๋Œ๋ฆฌ๋Š” ์ƒˆ ์ปค๋ฐ‹์„ ์ž‘์„ฑ

 


 

7. ๋ธŒ๋žœ์น˜์— ๋Œ€ํ•ด ์•Œ์•„๋ณด๊ธฐ

๋ธŒ๋žœ์น˜๋Š” ์ €์žฅ์†Œ์˜ ๊ฐ€์ง€์น˜๊ธฐ(ramification)์— ์ง€๋‚˜์ง€ ์•Š์œผ๋ฉฐ, ์ง€๊ธˆ๊นŒ์ง€ ๋ชจ๋“  ์ž‘์—…์€ ๋ธŒ๋žœ์น˜ 'master/main'์—์„œ ์ˆ˜ํ–‰๋˜์—ˆ๋‹ค. 

 

๊ธฐ๋ณธ์ ์œผ๋กœ ๋ ˆํฌ์ง€ํ† ๋ฆฌ์— ์ƒ์„ฑ๋œ ์ฒซ ๋ฒˆ์งธ ๋ธŒ๋žœ์น˜๋Š” ๋ ˆํฌ์ง€ํ† ๋ฆฌ์˜ ๋ฉ”์ธ ๋ธŒ๋žœ์น˜์ธ master/main ์ด๋‹ค.

 

7.1 ์™œ ๋ธŒ๋žœ์น˜๋ฅผ ์‚ฌ์šฉํ•˜๋Š”๊ฐ€?

์ฒ˜์Œ์—๋Š” ๋ณ„๊ฒƒ ์•„๋‹Œ ๊ฒƒ์ฒ˜๋Ÿผ ๋ณด์ผ ์ˆ˜ ์žˆ์ง€๋งŒ ๋ธŒ๋žœ์น˜๋Š” ํ”„๋กœ์ ํŠธ ๊ฐœ๋ฐœ์— ๋ง‰๋Œ€ํ•œ ํŒŒ์›Œ๋ฅผ ๊ฐ€์ง€๊ณ  ์žˆ๋‹ค.

 

์šฐ๋ฆฌ๊ฐ€ ์›น ํ”Œ๋žซํผ์„ ๊ฐœ๋ฐœํ•˜๊ณ  ์žˆ๊ณ , ์ƒˆ๋กœ์šด ๊ธฐ๋Šฅ์„ ํ…Œ์ŠคํŠธํ•˜๊ณ  ์‹ถ์ง€๋งŒ, ์šฐ๋ฆฌ์˜ ์ €์žฅ์†Œ๋Š” ์ด๋ฏธ ํ˜ธ์ŠคํŠธ๋˜์—ˆ๊ฑฐ๋‚˜ ๋‹ค๋ฅธ ์‚ฌ๋žŒ๋“ค๊ณผ ๊ณต์œ ํ•˜๊ณ  ์žˆ๊ณ , ์–ด๋–ค ๋ฌธ์ œ๊ฐ€ ์žˆ๋Š” ๋ณ€๊ฒฝ๋“ค์ด ๊ทธ๊ฒƒ๋“ค์—๊ฒŒ ๋‚˜์œ ๊ฒฝํ—˜์„ ์•ผ๊ธฐํ•  ์ˆ˜ ์žˆ๋‹ค๊ณ  ์ƒ๊ฐํ•ด๋ณด๋ผ. ์ด ์ƒํ™ฉ์—์„œ ์šฐ๋ฆฌ๋Š” ๋ฌด์—‡์„ ํ•  ์ˆ˜ ์žˆ์„๊นŒ?

 

ํ”„๋กœ์ ํŠธ ํด๋”๋ฅผ ๋ณต์‚ฌํ•˜์—ฌ ๋ถ™์—ฌ๋„ฃ๊ณ  ์ƒˆ๋กœ์šด "ํ…Œ์ŠคํŠธ ๋ฒ„์ „"์„ ๋งŒ๋“œ๋Š” ๊ฒƒ์— ๋Œ€ํ•ด ์ƒ๊ฐํ•ด๋ณธ ์ ์ด ์žˆ๋‹ค๋ฉด, ๋งž๋Š” ๋ง์ด๋‹ค! ์Œ, ๊ฑฐ์˜...

 

GIT๋ฅผ ์‚ฌ์šฉํ•˜๋ฉด, ์šฐ๋ฆฌ๋Š” ๋ธŒ๋žœ์น˜๋“ค๋กœ ๋น„์Šทํ•œ ์ผ์„ ํ•  ์ˆ˜ ์žˆ๋‹ค. ๋ธŒ๋žœ์น˜์ด๊ธฐ ๋•Œ๋ฌธ์—, ์šฐ๋ฆฌ๋Š” ๋‹จ์ˆœํžˆ "ํ…Œ์ŠคํŠธ"๋ผ๊ณ  ๋ถˆ๋ฆฌ๋Š” ์ƒˆ๋กœ์šด ๋ธŒ๋žœ์น˜๋ฅผ ๋งŒ๋“ค ์ˆ˜ ์žˆ๋‹ค. ๋”ฐ๋ผ์„œ ์šฐ๋ฆฌ ํ”„๋กœ์ ํŠธ์˜ ๋ฒ„์ „์„ ์™„์ „ํžˆ ๊ณ ๋ฆฝ๋œ ๋ธŒ๋žœ์น˜์—์„œ, main ๋ธŒ๋žœ์น˜์— ์˜ํ–ฅ์„ ์ฃผ์ง€ ์•Š๊ณ  ๋ฐ”๊ฟ€ ์ค€๋น„๋ฅผ ํ•œ๋‹ค.

 

 

 

7.2 ๋ธŒ๋žœ์น˜ ๋งŒ๋“ค๊ธฐ (git branch)

๋ธŒ๋žœ์น˜๋ฅผ ๋งŒ๋“œ๋Š” ๊ฒƒ์€ master/main ๋ธŒ๋žœ์น˜์— ์˜ํ–ฅ์„ ์ฃผ์ง€ ์•Š๊ณ  ๋…๋ฆฝ์ ์œผ๋กœ ์ž‘์—…ํ•  ์ˆ˜ ์žˆ๋Š” ์ €์žฅ์†Œ์˜ ๋ณ‘๋ ฌ ๋ณต์‚ฌ๋ณธ์„ ๋งŒ๋“œ๋Š” ๊ฒƒ์„ ์˜๋ฏธํ•œ๋‹ค. ์ด๋ฅผ ์œ„ํ•ด์„œ ์šฐ๋ฆฌ๋Š” ๋‹จ์ˆœํžˆ ์•„๋ž˜์˜ ๋ช…๋ น์–ด๋ฅผ ์‹คํ–‰ํ•˜๋ฉด ๋œ๋‹ค:

 

git branch [branch-name]

 

 

ํŠน์ • ๋ธŒ๋žœ์น˜์˜ ์ด๋ฆ„ ์—†์ด git branch ๋ช…๋ น์„ ์‹คํ–‰ํ•˜๋ ค๋ฉด ์ €์žฅ์†Œ์— ์‚ฌ์šฉ ๊ฐ€๋Šฅํ•œ ๋ธŒ๋žœ์น˜ ๋ชฉ๋ก์„ ํ‘œ์‹œํ•˜๋ฉฐ, "*"์˜ ํ‘œ์‹œ๋Š” ํ˜„์žฌ ์‚ฌ์šฉ ์ค‘์ธ ๋ธŒ๋žœ์น˜๋ฅผ ๋‚˜ํƒ€๋‚ธ๋‹ค.

 

git branch test ๋ช…๋ น์„ ์‹คํ–‰ํ•˜๊ธฐ ์ „์— git branch ๋ช…๋ น์€ master ๋ธŒ๋žœ์น˜๋งŒ ๋ฐ˜ํ™˜ํ•œ๋‹ค.

 

git checkout [branch-name]

 

git checkout test ๋ช…๋ น์„ ์‹คํ–‰ํ•œ ํ›„ ํ™œ์„ฑ ๋ธŒ๋žœ์น˜๊ฐ€ ์ „ํ™˜๋˜๋Š” ๊ฒƒ์„ ํ™•์ธํ•  ์ˆ˜ ์žˆ๋‹ค. ๊ทธ ์ˆœ๊ฐ„๋ถ€ํ„ฐ ๋ชจ๋“  ์ปค๋ฐ‹๋œ ์ •๋ณด๋Š” ๋ธŒ๋žœ์น˜ master/main ์— ์˜ํ–ฅ์„ ์ฃผ์ง€ ์•Š๊ณ  ์ €์žฅ์†Œ์˜ test ๋ธŒ๋žœ์น˜๋กœ ์ „์†ก๋œ๋‹ค.

 

 

ํ•„์š”ํ•œ ๋งŒํผ์˜ ๋ธŒ๋žœ์น˜๋ฅผ ์ƒ์„ฑํ•  ์ˆ˜ ์žˆ์œผ๋ฉฐ, ์•„๋ž˜ ๋ช…๋ น์„ ์‚ฌ์šฉํ•˜์—ฌ ๊ธฐ์กด ๋ธŒ๋žœ์น˜์™€ ์ƒํ˜ธ ์ž‘์šฉํ•  ์ˆ˜ ์žˆ๋‹ค:

git checkout -b [branch-name]
 -> ์ง€์ •๋œ ์ด๋ฆ„์œผ๋กœ ์ƒˆ ๋ธŒ๋žœ์น˜๋ฅผ ๋งŒ๋“ค๊ณ  ์ง์ ‘ ๊ทธ ๋ธŒ๋žœ์น˜๋กœ ์ „ํ™˜ํ•œ๋‹ค.
git branch -d [branch-name] -> ์ง€์ •ํ•œ branch๋ฅผ ์‚ญ์ œํ•œ๋‹ค.
git branch -m [new-name] -> ํ˜„์žฌ branch์˜ ์ด๋ฆ„์„ ์ง€์ •๋œ ์ด๋ฆ„์œผ๋กœ ๋ณ€๊ฒฝํ•œ๋‹ค.

 

 

7.3 ๋ธŒ๋žœ์น˜ ๋ณ‘ํ•ฉํ•˜๊ธฐ(git merge)

๋‹ค๋ฅธ ๋ธŒ๋žœ์น˜ ์ž‘์—…์„ ์™„๋ฃŒํ•˜๊ณ  ๋ณ€๊ฒฝํ•œ ๋‚ด์šฉ์ด ํ”„๋กœ์ ํŠธ์— ๋ฌธ์ œ๋ฅผ ์ผ์œผํ‚ค์ง€ ์•Š์•˜๋‹ค๊ณ  ํ™•์‹ ํ•œ๋‹ค๋ฉด, ํ˜„์žฌ ๋ธŒ๋žœ์น˜์˜ ๋ชจ๋“  ๋ณ€๊ฒฝ ์‚ฌํ•ญ์„ ์ ์šฉํ•˜์—ฌ master/main ๋ธŒ๋žœ์น˜๋กœ ๋ณ‘ํ•ฉํ•  ์ˆ˜ ์žˆ๋‹ค

 

๋ธŒ๋žœ์น˜๋ฅผ ๋ณ‘ํ•ฉํ•˜๋ ค๋ฉด ๋ณ€๊ฒฝ ์‚ฌํ•ญ์„ ๋ฐ›์„ ๋ธŒ๋žœ์น˜๋กœ ์ „ํ™˜ํ•˜๊ณ  ๋‹ค์Œ ๋ช…๋ น์„ ์‹คํ–‰ํ•ด์•ผ ํ•œ๋‹ค.

 

git merge [branch-name]
# ์ง€์ •๋œ ๋ธŒ๋žœ์น˜๋ฅผ ํ˜„์žฌ ํ™œ์„ฑ๋œ ๋ธŒ๋žœ์น˜๋กœ ๋ณ‘ํ•ฉ

 

์—ฌ๊ธฐ์„œ ์šฐ๋ฆฌ๋Š” branch 'test'์— ์žˆ๊ธฐ ๋•Œ๋ฌธ์— git checkout ๋ช…๋ น์–ด๋ฅผ ํ†ตํ•ด master ๋ธŒ๋žœ์น˜๋กœ ์ „ํ™˜ํ•ด์•ผ ํ•˜๋ฉฐ git merge ๋ช…๋ น์–ด๋ฅผ ๋ณ‘ํ•ฉํ•˜๊ณ  ์‹ถ์€ ๋ธŒ๋žœ์น˜ ์ด๋ฆ„๊ณผ ํ•จ๊ป˜ ์‹คํ–‰ํ•ด์•ผ ํ•œ๋‹ค. (์—ฌ๊ธฐ์„œ๋Š” 'test')

 

 

์ด๋ ‡๊ฒŒ ํ•˜๋ฉด test ๋ธŒ๋žœ์น˜์—์„œ ์ˆ˜ํ–‰๋œ ๋ชจ๋“  ์ž‘์—…(์ด ๊ฒฝ์šฐ style.css ํŒŒ์ผ ์ž‘์„ฑ)์ด master ๋ธŒ๋žœ์น˜์— ๋ณ‘ํ•ฉ๋œ๋‹ค.

 

 

 

7.4 ๋ณ‘ํ•ฉ ์ถฉ๋Œ

์„œ๋กœ ๋‹ค๋ฅธ ๋ธŒ๋žœ์น˜๋ฅผ ๊นƒ ๋จธ์ง€(git merge)๋กœ ๋ณ‘ํ•ฉํ•  ๋•Œ ๋™์ผํ•œ ํ–‰์—์„œ ํ•˜๋‚˜ ์ด์ƒ์˜ ํŒŒ์ผ์ด ๋ณ€๊ฒฝ๋˜์–ด ๋ณ‘ํ•ฉ์„ ์ž๋™์œผ๋กœ ์ˆ˜ํ–‰ํ•  ์ˆ˜ ์—†๋Š” ๊ฒฝ์šฐ์—์„œ ์ผ๋ถ€ ์ถฉ๋Œ์ด ๋ฐœ์ƒํ•  ์ˆ˜ ์žˆ๋‹ค.

 

 

 

์ด๋ ‡๊ฒŒ ๋˜๋ฉด git status ๋ช…๋ น์„ ์‹คํ–‰ํ•˜์—ฌ ์–ด๋–ค ํŒŒ์ผ์ด ์ถฉ๋Œํ•˜๋Š”์ง€ ํ™•์ธํ•  ์ˆ˜ ์žˆ๋‹ค.

 

 

 

์šฐ๋ฆฌ๋Š” ๋ณ‘ํ•ฉ์„ ์ง„ํ–‰ํ•˜๊ธฐ ์ „์— ์–ด๋–ค ๋ณ€๊ฒฝ ์‚ฌํ•ญ์ด ๋ฐœ์ƒํ•ด์•ผ ํ•˜๋Š”์ง€ ์ •์˜ํ•˜๊ฑฐ๋‚˜ ๋ณ€๊ฒฝ ์‚ฌํ•ญ์„ ๊ฒ€ํ† ํ•˜์—ฌ ์ƒํ˜ธ ํ˜ธํ™˜๋˜๋„๋ก ์ถฉ๋Œ์„ ํ•ด๊ฒฐํ•ด์•ผ ํ•œ๋‹ค. ์ด๋ฅผ ์œ„ํ•ด GIT๋Š” ์ถฉ๋Œํ•˜๋Š” ํŒŒ์ผ์— ๋งˆ์ปค๋ฅผ ์‚ฝ์ž…ํ•˜์—ฌ ํ•ด๊ฒฐ์„ ๋•๋Š”๋‹ค.

 

 

 

์ถฉ๋Œ์„ ํ•ด๊ฒฐํ•œ ํ›„ ์ˆ˜์ •๋œ ํŒŒ์ผ์„ ๋‹ค์‹œ ์Šคํ…Œ์ด์ง€์— ์˜ฌ๋ ค๋†“๊ณ  ์ƒˆ๋กœ์šด ์ถฉ๋Œ ์—†๋Š” ๋ฒ„์ „์„ ์ปค๋ฐ‹ํ•˜๊ณ  git merge ๋ช…๋ น์„ ๋‹ค์‹œ ์‹คํ–‰ํ•˜๋ฉด ๋ฌธ์ œ ์—†์ด ์„ฑ๊ณต์ ์œผ๋กœ ๋ณ‘ํ•ฉํ•  ์ˆ˜ ์žˆ๋‹ค.

 


 

8. ์›๊ฒฉ ์ €์žฅ์†Œ์™€ ๋™๊ธฐํ™”

์šฐ๋ฆฌ๋Š” ์ด๋ฏธ ๋กœ์ปฌ ์ €์žฅ์†Œ๋ฅผ ์›๊ฒฉ ์ €์žฅ์†Œ์— ์—ฐ๊ฒฐํ•˜๊ณ  ๋ชจ๋“  ์ž‘์—…์„ ์›๊ฒฉ์œผ๋กœ ๋™๊ธฐํ™”ํ•˜์—ฌ ์ตœ์‹  ์ƒํƒœ๋กœ ์œ ์ง€ํ•˜๋Š” ๊ฒƒ์ด ๊ฐ€๋Šฅํ•˜๋‹ค๋Š” ๊ฒƒ์„ ์•Œ๊ณ  ์žˆ๋‹ค.

 

์ด๋ฅผ ์œ„ํ•ด git push ๋ช…๋ น์–ด๋ฅผ ์‹คํ–‰ํ•ด ๋กœ์ปฌ ์ €์žฅ์†Œ๋กœ๋ถ€ํ„ฐ ๋ชจ๋“  ์ปค๋ฐ‹์„ ์›๊ฒฝ ์ €์žฅ์†Œ๋กœ ๋ณด๋‚ด์•ผ ํ•œ๋‹ค. ๊ทธ๋Ÿฌ๋‚˜ ๋จผ์ € ์›๊ฒฉ ์ €์žฅ์†Œ๋ฅผ ๊ตฌ์„ฑํ•ด์•ผ ํ•œ๋‹ค.

 

8.1 ์›๊ฒฉ ์ €์žฅ์†Œ ๊ตฌ์„ฑํ•˜๊ธฐ

 

์›๊ฒฉ ์ €์žฅ์†Œ๋ฅผ ๊ตฌ์„ฑํ•˜๋Š” ๊ฒƒ์€ ๋งค์šฐ ๊ฐ„๋‹จํ•˜๋‹ค. ์šฐ๋ฆฌ๋Š” ์ด๋ฅผ ์œ„ํ•ด Github๋ฅผ ์‚ฌ์šฉํ•  ๊ฒƒ์ด๋‹ค.

 

๋จผ์ € GitHub ๊ณ„์ •์—์„œ ๋นˆ ์ €์žฅ์†Œ๋ฅผ ์ƒˆ๋กœ ์‹œ์ž‘ํ•ด์•ผ ํ•œ๋‹ค(์ด๋ฆ„์„ ์„ ํƒํ•˜๊ณ  "Creating repository"๋ฅผ ํด๋ฆญํ•˜๊ธฐ๋งŒ ํ•˜๋ฉด ๋œ๋‹ค) :

 

 

 

๋‹ค์Œ์œผ๋กœ ์›๊ฒฉ ์ €์žฅ์†Œ์™€ ๋กœ์ปฌ ์ €์žฅ์†Œ์™€์˜ ๊ด€๊ณ„๋ฅผ ๋‹ค์Œ ๋ช…๋ น์–ด๋ฅผ ์šฐ๋ฆฌ์˜ ๋กœ์ปฌ ์ €์žฅ์†Œ์—์„œ ์‹คํ–‰ํ•ด ๊ตฌ์„ฑํ•ด์•ผ ํ•œ๋‹ค.

 

git remote add origin [remote-repository-url]

 

 

 

 

git remote -v : ๋กœ์ปฌ ์ €์žฅ์†Œ์— ์—ฐ๊ฒฐ๋˜์–ด ์žˆ๋Š” ์›๊ฒฉ ์ €์žฅ์†Œ์˜ URL์„ ๋ณด์—ฌ์ค€๋‹ค.

 

 

์›๊ฒฉ ์ €์žฅ์†Œ๊ฐ€ ์ ์ ˆํ•˜๊ฒŒ ์—ฐ๊ฒฐ๋˜์—ˆ๋‹ค๋ฉด, ์šฐ๋ฆฌ๋Š” ์šฐ๋ฆฌ์˜ ๋กœ์ปฌ ๋ธŒ๋žœ์น˜ master/main์˜ ์ด๋ฆ„์„ git branch -m main ๋ช…๋ น์–ด๋ฅผ ํ†ตํ•ด  main์œผ๋กœ ๋ฐ”๊ฟ”์•ผ ํ•œ๋‹ค(๋‹น์‹ ์˜ ๋กœ์ปฌ ๋ธŒ๋žœ์น˜๊ฐ€ ์ด๋ฏธ main์œผ๋กœ ๋ถˆ๋ฆฌ๊ณ  ์žˆ๋‹ค๋ฉด ์ด ๋‹จ๊ณ„๋ฅผ ๋ฌด์‹œํ•˜๋ผ).

 

 

 

์šฐ๋ฆฌ๊ฐ€ push ํ•˜๋Š” ๋กœ์ปฌ ์ €์žฅ์†Œ์˜ ๋ฉ”์ธ ๋ธŒ๋žœ์น˜๋ฅผ ์›๊ฒฉ ์ €์žฅ์†Œ์˜ ๋ฉ”์ธ ๋ธŒ๋žœ์น˜์™€ ๋™์ผํ•œ ์ด๋ฆ„์œผ๋กœ ์œ ์ง€ํ•˜๋Š” ๊ฒƒ์ด ์ค‘์š”ํ•˜๋‹ค.

 

 

๋งˆ์ง€๋ง‰์œผ๋กœ ์œ„์˜ ๋‹จ๊ณ„๋ฅผ ์™„๋ฃŒํ•œ ํ›„ ๋‹ค์Œ ๋ช…๋ น์„ ์‚ฌ์šฉํ•˜์—ฌ ๋กœ์ปฌ ์ €์žฅ์†Œ๋ฅผ ์ฒ˜์Œ์œผ๋กœ ์›๊ฒฉ ์ €์žฅ์†Œ์™€ ๋™๊ธฐํ™”ํ•  ์ˆ˜ ์žˆ๋‹ค:

 

git push -u origin main

 

 

 

 

git push-u origin main ๋ช…๋ น์„ ์‹คํ–‰ํ•  ๋•Œ GitHub credentials(์‚ฌ์šฉ์ž ๋ฐ ์•ก์„ธ์Šค ํ† ํฐ)์„ ์ž…๋ ฅํ•ด์•ผ ํ•  ์ˆ˜๋„ ์žˆ๋‹ค.

 

๋งŒ์•ฝ Github ์•ก์„ธ์Šค ํ† ํฐ์ด ๋ฌด์—‡์ธ์ง€ ๋ชจ๋ฅธ๋‹ค๊ฑฐ๋‚˜ ํ•˜๋‚˜์˜ ์•ก์„ธ์Šค ํ† ํฐ์„ ์„ค์ •ํ•˜์ง€ ์•Š์•˜๋‹ค๋ฉด ์—ฌ๊ธฐ๋ฅผ ํด๋ฆญํ•˜๋ผ.

GitHub CLI๋ฅผ ์‚ฌ์šฉํ•ด ์ธ์ฆ์„ ๊ตฌ์„ฑํ•จ์œผ๋กœ์จ ์ด ๋ฌธ์ œ๋ฅผ ํ•ด๊ฒฐํ•  ์ˆ˜๋„ ์žˆ๋‹ค. ์—ฌ๊ธฐ๋ฅผ ํด๋ฆญํ•˜์—ฌ ๋ฐฉ๋ฒ•์„ ์•Œ์•„๋ณด์„ธ์š”.

 

 

์ธ์ฆ(Authenticating)์„ ํ•œ ํ›„์—๋Š” git push ์‹คํ–‰์ด ์„ฑ๊ณต์ ์œผ๋กœ ๋˜์–ด์•ผ ํ•˜๊ณ  ๋กœ์ปฌ ์ €์žฅ์†Œ์˜ ๋ชจ๋“  ์ปค๋ฐ‹์ด ์›๊ฒฉ ์ €์žฅ์†Œ์™€ ๋™๊ธฐํ™”๋œ๋‹ค.

 

 

 

 

 

 

8.2  ์ฒ˜์Œ ์ดํ›„ Git push (git push)

 

์œ„์˜ ๋ชจ๋“  ๋‹จ๊ณ„๋ฅผ ๊ฑฐ์นœ ํ›„์—๋Š” ์•„๋ž˜์™€ ๊ฐ™์ด ๋ณ„๋„์˜ ํŒŒ๋ผ๋ฏธํ„ฐ ์—†์ด git push ๋ช…๋ น๋งŒ์œผ๋กœ ์ƒˆ๋กœ์šด ๋™๊ธฐํ™”๋ฅผ ํ•  ์ˆ˜ ์žˆ๋‹ค.

 

 

 

 

 

์ด ๊ฒฝ์šฐ github CLI๋ฅผ ์ด์šฉํ•˜์—ฌ git push ๋ช…๋ น ์‹คํ–‰์— ํ•„์š”ํ•œ ์ธ์ฆ์„ ๊ฑด๋„ˆ๋›ฐ์—ˆ๋‹ค. ์—ฌ๊ธฐ๋ฅผ ํด๋ฆญํ•˜๋ฉด ๋ฐฉ๋ฒ•์„ ์•Œ ์ˆ˜ ์žˆ๋‹ค.

 

 

8.3  ๋กœ์ปฌ ์ €์žฅ์†Œ ์—…๋ฐ์ดํŠธํ•˜๊ธฐ (git pull)

 

๋ถ„์‚ฐ๋œ ์›๊ฒฉ ์ €์žฅ์†Œ๋ฅผ ์‚ฌ์šฉํ•˜๋ฉด ์›๊ฒฉ์œผ๋กœ ๋ณ€๊ฒฝํ•  ์ˆ˜ ์žˆ์œผ๋ฏ€๋กœ (์›๊ฒฉ ์ €์žฅ์†Œ์—์„œ ์ง์ ‘) ๋กœ์ปฌ ์ €์žฅ์†Œ๊ฐ€ ์˜ค๋ž˜๋œ ์ƒํƒœ์ผ ์ˆ˜ ์žˆ๋‹ค.

 

์ด๋ฅผ ๊ณ ๋ คํ•  ๋•Œ, ๋กœ์ปฌ ์ €์žฅ์†Œ๋ฅผ ์—…๋ฐ์ดํŠธํ•˜๊ณ  ์›๊ฒฉ ์ €์žฅ์†Œ์—์„œ ๋ณ€๊ฒฝํ•œ ๋‚ด์šฉ์„ ๋™๊ธฐํ™”ํ•˜๋Š” ๊ฒƒ์ด ๋งค์šฐ ์ค‘์š”ํ•˜๋ฉฐ ๋กœ์ปฌ ํ”„๋กœ์ ํŠธ๋ฅผ ํ•ญ์ƒ ์›๊ฒฉ ์ €์žฅ์†Œ์—์„œ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๋Š” ์ตœ์‹  ๋ฒ„์ „์œผ๋กœ ์œ ์ง€ํ•ด์•ผ ํ•œ๋‹ค. ์ด ์ž‘์—…์„ ์ˆ˜ํ–‰ํ•˜๊ธฐ ์œ„ํ•ด ๋‹ค์Œ ๋ช…๋ น์„ ์‹คํ–‰ํ•œ๋‹ค:

 

 

git pull

 

 

์ƒˆ๋กœ์šด README.md ํŒŒ์ผ์ด ์šฐ๋ฆฌ์˜ ์›๊ฒฉ ์ €์žฅ์†Œ์— ์ง์ ‘ ์ƒ์„ฑ๋˜์–ด ์šฐ๋ฆฌ์˜ ๋กœ์ปฌ ์ €์žฅ์†Œ๊ฐ€ ์—…๋ฐ์ดํŠธ๋˜์ง€ ์•Š์•˜๋‹ค๊ณ  ์ƒ๊ฐํ•ด๋ณด๋ผ.

 

 

 

์œ„์—์„œ ์–ธ๊ธ‰ํ•œ ๊ฒƒ์ฒ˜๋Ÿผ git pull์„ ์‚ฌ์šฉํ•˜์—ฌ ์›๊ฒฉ ์ €์žฅ์†Œ๋กœ๋ถ€ํ„ฐ์˜ ๋ณ€๊ฒฝ ์‚ฌํ•ญ์„ ๋กœ์ปฌ ์ €์žฅ์†Œ ๋‚ด์—์„œ ๋™๊ธฐํ™”ํ•  ์ˆ˜ ์žˆ๋‹ค. 

 

 

 

 

์ฒ˜์Œ 7๊ฐœ์˜ ํ–‰์ด git pull ๋ช…๋ น์„ ์‹คํ–‰ํ•  ๋•Œ git fetch ๋ช…๋ น์˜ return ๊ฐ’์ด๋‹ค. ์ฆ‰, git fetch ๋ช…๋ น์„ ๋จผ์ € ์‹คํ–‰ํ•˜์ง€ ์•Š๊ณ  git pull ๋ช…๋ น์„ ์‹คํ–‰ํ•˜๋ฉด GIT๋Š” ๋‘˜ ๋‹ค ํ•จ๊ป˜ ์‹คํ–‰ํ•ด ์›๊ฒฉ ์ €์žฅ์†Œ์—์„œ ์—…๋ฐ์ดํŠธ๋ฅผ ์ฐพ์•„ ๋กœ์ปฌ ์ €์žฅ์†Œ์— ๋™๊ธฐํ™”ํ•œ๋‹ค.

git fetch -> ์›๊ฒฉ ์ €์žฅ์†Œ์—์„œ ์—…๋ฐ์ดํŠธ๋ฅผ ๊ฐ€์ ธ์˜ค์ง€๋งŒ ๋กœ์ปฌ ์ €์žฅ์†Œ๋ฅผ ๋™๊ธฐํ™”ํ•˜์ง€๋Š” ์•Š์Šต๋‹ˆ๋‹ค(git pull์ด ํ•„์š”ํ•จ).

 

 


 

9. ๊ฒฐ๋ก 

์—ฌํƒœ๊นŒ์ง€์˜ ๋ชจ๋“  ๊ฒƒ์€ GIT์ด ํ”„๋กœ๊ทธ๋ž˜๋จธ์˜ ์ผ์ƒ์ƒํ™œ์—์„œ ํ•„์š”ํ•œ ๋ฒ„์ „ ์ œ์–ด ์‹œ์Šคํ…œ์ด๋ผ๋Š” ํ™•์‹ ์„ ๊ฐ–๊ฒŒ ํ•˜๋ฉฐ, GIT์˜ ์ฃผ์š” ๋ช…๋ น๊ณผ ์‚ฌ์šฉ๋ฒ•์„ ์•„๋Š” ๊ฒƒ์ด ์šฐ๋ฆฌ์˜ ๊ธฐ์ˆ ์  ์—ฐ๊ณต์„œ์—ด์˜ ์ „ํ™˜์ ์ด ๋  ์ˆ˜ ์žˆ๋‹ค๋Š” ์ ์ด๋‹ค. ๋งˆ์ง€๋ง‰์œผ๋กœ, ๋กœ์ปฌ ๋ฐ ์›๊ฒฉ ์ €์žฅ์†Œ๋ฅผ ๋™๊ธฐํ™”ํ•˜๊ณ  ์—…๋ฐ์ดํŠธํ•˜๋ฉฐ ์ง€๊ธˆ๊นŒ์ง€ ๋ฐฐ์šด ๋ชจ๋“  ๊ฒƒ์„ ๋ฐ”ํƒ•์œผ๋กœ ์ด ๋†€๋ผ์šด ๋ฒ„์ „ ์ œ์–ด ์‹œ์Šคํ…œ์˜ ์‹ค์šฉ์„ฑ์„ ๊ณ„์† ๋ฐœ์ „์‹œํ‚ฌ ์ค€๋น„๊ฐ€ ๋˜์–ด ์žˆ๋‹ค.

 


10. ์ฐธ์กฐ

https://web.dev/articles/dom-size-and-interactivity

 

ํฐ DOM ํฌ๊ธฐ๊ฐ€ ์ƒํ˜ธ์ž‘์šฉ์— ๋ฏธ์น˜๋Š” ์˜ํ–ฅ๊ณผ ์ด์— ๋Œ€ํ•ด ์ทจํ•  ์ˆ˜ ์žˆ๋Š” ์กฐ์น˜  |  Articles  |  web.dev

ํฐ DOM ํฌ๊ธฐ๋Š” ์ƒํ˜ธ์ž‘์šฉ์ด ๋น ๋ฅธ์ง€ ์—ฌ๋ถ€์— ์˜ํ–ฅ์„ ๋ฏธ์น  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. DOM ํฌ๊ธฐ์™€ INP์˜ ๊ด€๊ณ„, DOM ํฌ๊ธฐ๋ฅผ ์ค„์ด๊ธฐ ์œ„ํ•ด ์ทจํ•  ์ˆ˜ ์žˆ๋Š” ์กฐ์น˜ ๋ฐ ํŽ˜์ด์ง€์— DOM ์š”์†Œ๊ฐ€ ๋งŽ์€ ๊ฒฝ์šฐ ๋ Œ๋”๋ง ์ž‘์—…์„ ์ œํ•œํ•˜๋Š” ๋‹ค

web.dev



๐Ÿ—ฃ๏ธ ํฌ๊ธฐ๊ฐ€ ํฐ ๋”์€ ์šฐ๋ฆฌ๊ฐ€ ์ƒ๊ฐํ•˜๋Š” ๊ฒƒ๋ณด๋‹ค ์ƒํ˜ธ์ ์œผ๋กœ ์˜ํ–ฅ์„ ๋ผ์น  ๊ฐ€๋Šฅ์„ฑ์ด ๋†’๋‹ค. ์ด ๊ฐ€์ด๋“œ๋Š” ๊ทธ ์ด์œ ์— ๋Œ€ํ•ด ์„ค๋ช…ํ•˜๊ณ  ์ด์— ๋Œ€ํ•ด ์šฐ๋ฆฌ๊ฐ€ ์ทจํ•  ์ˆ˜ ์žˆ๋Š” ํ–‰๋™์— ๋Œ€ํ•ด ์„ค๋ช…ํ•œ๋‹ค.

์›น ํŽ˜์ด์ง€๋ฅผ ๋งŒ๋“ค ๋•Œ ํŽ˜์ด์ง€์— DOM(Document object model)์ด ์žˆ๋‹ค๋Š” ์ ์€ ๋ช…๋ฐฑํ•œ ์‚ฌ์‹ค์ด๋‹ค.

DOM์€ ํŽ˜์ด์ง€์˜ HTML ๊ตฌ์กฐ๋ฅผ ๋‚˜ํƒ€๋‚ด๊ณ  ํŽ˜์ด์ง€์˜ ๊ตฌ์กฐ์™€ ๋‚ด์šฉ์— ์ ‘๊ทผํ•˜๋„๋ก ์ž๋ฐ”์Šคํฌ๋ฆฝํŠธ์™€ CSS๋ฅผ ๋ณด๋‚ธ๋‹ค.

๊ทธ๋Ÿฌ๋‚˜ ๋ฌธ์ œ๋Š” DOM์˜ ์‚ฌ์ด์ฆˆ๊ฐ€ ๋ธŒ๋ผ์šฐ์ €๊ฐ€ ํŽ˜์ด์ง€๋ฅผ ๋น ๋ฅด๊ณ  ํšจ์œจ์ ์œผ๋กœ ๋ Œ๋”๋งํ•˜๋Š”๋ฐ์— ์˜ํ–ฅ์„ ์ค€๋‹ค๋Š” ์ ์ด๋‹ค.
์ผ๋ฐ˜์ ์œผ๋กœ DOM์ด ํด์ˆ˜๋ก ์ฒ˜์Œ์— ํ•ด๋‹น ํŽ˜์ด์ง€๋ฅผ ๋ Œ๋”๋งํ•˜๊ณ  ๋‚˜์ค‘์— ํŽ˜์ด์ง€ ๋ผ์ดํ”„์‚ฌ์ดํด์—์„œ ๋ Œ๋”๋ง์„ ์—…๋ฐ์ดํŠธํ•˜๋Š”๋ฐ์— ๋” ๋งŽ์€ ๋น„์šฉ์ด ๋“ ๋‹ค.

์ด๋Š” DOM์„ ์ˆ˜์ •ํ•˜๊ณ  ์—…๋ฐ์ดํŠธํ•˜๋Š” ์ƒํ˜ธ ์ž‘์šฉ์ด ๋งŽ์€ ํŽ˜์ด์ง€์—์„œ ๋น ๋ฅธ ์‘๋‹ต์—์„œ ๋ฏธ์น˜๋Š” ์˜ํ–ฅ์ด ๋งŽ์€ ๋ ˆ์ด์•„์›ƒ ์ž‘์—…์„ ๋‹ค๋ฃฐ ๋•Œ ํฐ DOM์ด ๋ฌธ์ œ๊ฐ€ ๋œ๋‹ค.

๋น„์šฉ์ด ๋งŽ์ด ๋“œ๋Š” ๋ ˆ์ด์•„์›ƒ ์ž‘์—…์€ ํŽ˜์ด์ง€์˜ INP(Interaction to Next Page)์— ์˜ํ–ฅ์„ ๋ฏธ์นœ๋‹ค. ๋งŒ์•ฝ ํŽ˜์ด์ง€๊ฐ€ ์œ ์ € ์ƒํ˜ธ์ž‘์šฉ์— ๋น ๋ฅด๊ฒŒ ๋ฐ˜์‘ํ•˜๋„๋ก ํ•˜๋ ค๋ฉด DOM์˜ ํฌ๊ธฐ๋ฅผ ํ•„์š”ํ•œ ๋งŒํผ๋งŒ ์œ ์ง€ํ•˜๋Š” ๊ฒƒ์ด ์ค‘์š”ํ•˜๋‹ค.

โ—พ๏ธ ์–ธ์ œ ํŽ˜์ด์ง€์˜ DOM์˜ ํฌ๊ธฐ๊ฐ€ ์ปค์งˆ๊นŒ?

 

A: ํ•ต์‹ฌ ์šฉ์–ด: DOM ์š”์†Œ์™€ DOM ๋…ธ๋“œ์˜ ์ฐจ์ด์ ์„ ์•„๋Š” ๊ฒƒ์€ ์ค‘์š”ํ•˜๋‹ค. DOM ์š”์†Œ๋Š” DOM ํŠธ๋ฆฌ์˜ ํŠน์ • HTML ์š”์†Œ๋ฅผ ๋‚˜ํƒ€๋‚ธ๋‹ค. ๊ทธ๋ฆฌ๊ณ  DOM ๋…ธ๋“œ๋Š” DOM ์š”์†Œ์˜ ์šฉ์–ด์™€ ์ค‘๋ณต๋˜๋Š” ์˜๋ฏธ๋ฅผ ๊ฐ–์ง€๋งŒ ๊ทธ๊ฒƒ์˜ ์ •์˜๋Š” ์ฃผ์„, ๊ณต๋ฐฑ ๋ฐ ํ…์ŠคํŠธ๋กœ ํ™•์žฅ๋œ๋‹ค. Lighthouse์˜ DOM ํฌ๊ธฐ ์ธก์ •์€ DOM ๋…ธ๋“œ๋ฅผ ์ฐธ์กฐํ•˜์ง€๋งŒ ์ด ๊ฐ€์ด๋“œ์—์„œ๋Š” ๊ฐ€๋Šฅํ•  ๋•Œ๋งˆ๋‹ค DOM ๋…ธ๋“œ๋ณด๋‹ค DOM ์š”์†Œ๋ฅผ ์ฐธ์กฐํ•  ๊ฒƒ์ด๋‹ค.


Lighthouse์— ๋”ฐ๋ฅด๋ฉด ํŽ˜์ด์ง€์˜ DOM์‚ฌ์ด์ฆˆ๊ฐ€ 1,400 ๋…ธ๋“œ๋ฅผ ๋„˜์„๋•Œ ๊ณผ๋„ํ•˜๋‹ค๊ณ  ๋ณธ๋‹ค. Lighthouse๋Š” DOM์ด 800๋…ธ๋“œ๋ฅผ ๋„˜์œผ๋ฉด ๊ฒฝ๊ณ ๋ฅผ ๋ณด๋‚ด๊ธฐ ์‹œ์ž‘ํ•œ๋‹ค.

๋‹ค์Œ HTML์„ ์˜ˆ๋กœ ๋“ค์–ด ๋ณด๊ฒ ๋‹ค:

<ul>
  <li>List item one.</li>
  <li>List item two.</li>
  <li>List item three.</li>
</ul>


์œ„ ์ฝ”๋“œ์—๋Š” 4๊ฐœ์˜ DOM ์š”์†Œ: <ul> ์š”์†Œ์™€ 3๊ฐœ์˜ ํ•˜์œ„ ์š”์†Œ <li>๊ฐ€ ์žˆ์Šต๋‹ˆ๋‹ค. ๋‹น์‹ ์˜ ์›น ํŽ˜์ด์ง€์—๋Š” ํ™•์‹คํžˆ ์ด๋ณด๋‹ค ๋” ๋งŽ์€ ๋…ธ๋“œ๊ฐ€ ์žˆ์„ ๊ฒƒ์ด๊ธฐ ๋•Œ๋ฌธ์— DOM ํฌ๊ธฐ๋ฅผ ํ™•์ธํ•˜๊ธฐ ์œ„ํ•ด ๋ฌด์—‡์„ ํ•  ์ˆ˜ ์žˆ๋Š”์ง€ ์ดํ•ดํ•˜๋Š” ๊ฒƒ์ด ์ค‘์š”ํ•ฉ๋‹ˆ๋‹ค. ๋”ฐ๋ผ์„œ ํŽ˜์ด์ง€์˜ DOM์„ ๊ฐ€๋Šฅํ•œ ํ•œ ์ž‘๊ฒŒ ๋งŒ๋“  ํ›„ ๋ Œ๋”๋ง ์ž‘์—…์„ ์ตœ์ ํ™”ํ•˜๊ธฐ ์œ„ํ•œ ๋‹ค๋ฅธ ์ „๋žต๋ฟ๋งŒ ์•„๋‹ˆ๋ผ DOM ํฌ๊ธฐ๋ฅผ ํ™•์ธํ•˜๊ธฐ ์œ„ํ•ด ์šฐ๋ฆฌ๊ฐ€ ์–ด๋–ค ๊ฒƒ์„ ํ•  ์ˆ˜ ์žˆ๋Š”์ง€ ์ดํ•ดํ•˜๋Š” ๊ฒƒ์ด ์ค‘์š”ํ•˜๋‹ค.

โ—พ๏ธํฌ๊ธฐ๊ฐ€ ํฐ DOM์ด ์–ด๋–ป๊ฒŒ ํŽ˜์ด์ง€ ์„ฑ๋Šฅ์— ์˜ํ–ฅ์„ ๋ฏธ์น ๊นŒ?


ํฐ DOM์€ ๋‹ค์Œ๊ณผ ๊ฐ™์ด ๋ช‡ ๊ฐ€์ง€ ๋ฐฉ์‹์œผ๋กœ ํŽ˜์ด์ง€ ์„ฑ๋Šฅ์— ์˜ํ–ฅ์„ ๋ฏธ์นœ๋‹ค.
1. ํŽ˜์ด์ง€๊ฐ€ ์ดˆ๊ธฐ ๋ Œ๋”๋ง๋˜๋Š” ๋™์•ˆ CSS๊ฐ€ ํŽ˜์ด์ง€์— ์ ์šฉ๋˜๋ฉด CSSOM(CSS ๊ฐœ์ฒด ๋ชจ๋ธ)์ด๋ผ๋Š” DOM๊ณผ ์œ ์‚ฌํ•œ ๊ตฌ์กฐ๊ฐ€ ์ƒ์„ฑ๋œ๋‹ค. CSS ์…€๋ ‰ํ„ฐ์˜ ๊ตฌ์ฒด์„ฑ์ด ์ฆ๊ฐ€ํ•˜๋ฉด์„œ CSSOM์€ ๋” ๋ณต์žกํ•ด์ง€๊ณ  ์›น ํŽ˜์ด์ง€๋ฅผ ํ™”๋ฉด์— ๊ทธ๋ฆฌ๋Š” ๋ฐ์— ํ•„์š”ํ•œ ๋ ˆ์ด์•„์›ƒ, ์Šคํƒ€์ผ๋ง, ํ•ฉ์น˜๊ธฐ ๋ฐ ํŽ˜์ธํŠธ ์ž‘์—…์„ ์‹คํ–‰ํ•˜๋Š” ๋ฐ์— ๋” ๋งŽ์€ ์‹œ๊ฐ„์ด ํ•„์š”ํ•˜๋‹ค. ์ด ์ถ”๊ฐ€ ์ž‘์—…์œผ๋กœ ์ธํ•ด ํŽ˜์ด์ง€ ๋กœ๋“œ ์ค‘ ์ดˆ๊ธฐ์— ๋ฐœ์ƒํ•˜๋Š” ์ƒํ˜ธ ์ž‘์šฉ์— ๋Œ€ํ•œ ๋Œ€๊ธฐ ์‹œ๊ฐ„์ด ๋Š˜์–ด๋‚œ๋‹ค.

2. DOM์„ ์ˆ˜์ •ํ•˜๊ฑฐ๋‚˜ ์š”์†Œ ์‚ฝ์ž… ํ˜น์€ ์‚ญ์ œ ๋˜๋Š” DOM ๋‚ด์šฉ๊ณผ ์Šคํƒ€์ผ ์ˆ˜์ •๊ณผ ๊ฐ™์€ ์ผ์ด ์ผ์–ด๋‚˜๋ฉด ์ด ์—…๋ฐ์ดํŠธ๋“ค์„ ๋ Œ๋”๋งํ•˜๋Š” ์ž‘์—…์— ๋งค์šฐ ๋งŽ์€ ๋น„์šฉ์ด ์†Œ์š”๋  ์ˆ˜ ์žˆ๋‹ค. CSS ์…€๋ ‰ํ„ฐ์˜ ๊ตฌ์ฒด์„ฑ ์ฆ๊ฐ€๋Š” ํŽ˜์ด์ง€์˜ ์ดˆ๊ธฐ ๋ Œ๋”๋ง๊ณผ ๋งˆ์ฐฌ๊ฐ€์ง€๋กœ HTML ์š”์†Œ๊ฐ€ ์ƒํ˜ธ์ž‘์šฉ์˜ ๊ฒฐ๊ณผ๋กœ DOM์— ์‚ฝ์ž…๋  ๋•Œ ๋ Œ๋”๋ง ์ž‘์—…์— ์ถ”๊ฐ€๋  ์ˆ˜ ์žˆ๋‹ค. 
 
3. JavaScript๊ฐ€ DOM์„ ์ฟผ๋ฆฌํ•  ๋•Œ DOM ์š”์†Œ์— ๋Œ€ํ•œ ์ฐธ์กฐ๋Š” ๋ฉ”๋ชจ๋ฆฌ์— ์ €์žฅ๋œ๋‹ค. ์˜ˆ๋ฅผ ๋“ค์–ด document.querySelectorAll์„ ํ˜ธ์ถœํ•ด ๋ชจ๋“  <div>์„ ํŽ˜์ด์ง€์—์„œ ์„ ํƒํ•  ๋•Œ,  ๋งŽ์€ ์ˆ˜์˜ DOM์š”์†Œ๋ฅผ ๋ฐ˜ํ™˜ํ•˜๋ฉด ๋ฉ”๋ชจ๋ฆฌ ๋น„์šฉ์ด ์ƒ๋‹นํ•  ์ˆ˜ ์žˆ๋‹ค.
 

Chorome ๊ฐœ๋ฐœ์ž ๋„๊ตฌ ์•ˆ์— ์žˆ๋Š” ํ”„๋กœํŒŒ์ผ๋Ÿฌ์— ํ‘œ์‹œ๋œ ๊ธด ์ž‘์—…์ด๋‹ค. ํ‘œ์‹œ๋œ ๊ธด ์ž‘์—…์€ JavaScript๋ฅผ ํ†ตํ•ด DOM ์š”์†Œ๋ฅผ ๋Œ€๊ทœ๋ชจ DOM์— ์‚ฝ์ž…ํ•˜๋ฉด์„œ ๋ฐœ์ƒํ•œ๋‹ค.

 
๋ชจ๋‘ ์ƒํ˜ธ ์ž‘์šฉ์— ์˜ํ–ฅ์„ ๋ฏธ์น˜์ง€๋งŒ ์œ„ ๋ชฉ๋ก ์ค‘ ๋‘ ๋ฒˆ์งธ ํ•ญ๋ชฉ์ด ํŠนํžˆ ์ค‘์š”ํ•˜๋‹ค. ์ƒํ˜ธ์ž‘์šฉ๋“ค์— ์˜ํ•ด DOM์ด ๋ณ€๊ฒฝ๋˜๋ฉด ํŽ˜์ด์ง€์˜ ์ข‹์ง€ ์•Š์€ INP์— ๊ธฐ์—ฌํ•  ์ˆ˜ ์žˆ๋Š” ์ž‘์—…์ด ์‹œ์ž‘๋  ์ˆ˜๋„ ์žˆ๋‹ค.

โ—พ๏ธ์–ด๋–ป๊ฒŒ DOM์‚ฌ์ด์ฆˆ๋ฅผ ์ธก์ •ํ• ๊นŒ?

 

๋‹น์‹ ์€ ๋‹ค์–‘ํ•œ ๋ฐฉ๋ฒ•์œผ๋กœ DOM์‚ฌ์ด์ฆˆ๋ฅผ ์ธก์ •ํ•  ์ˆ˜ ์žˆ๋‹ค. ์ฒซ ๋ฒˆ์งธ ๋ฐฉ๋ฒ•์€ Lighthouse๋ฅผ ์‚ฌ์šฉํ•˜๋Š” ๋ฐฉ๋ฒ•์ด๋‹ค. Lighthouse์—์„œ ๊ฒ€์‚ฌ๋ฅผ ์‹คํ–‰ํ•˜๋ฉด ํ˜„์žฌ ํŽ˜์ด์ง€์˜ DOM์— ๋Œ€ํ•œ ํ†ต๊ณ„๊ฐ€ 'Diagnostics' ์ œ๋ชฉ ์•„๋ž˜ 'Avoid an excessive DOM size(๊ณผ๋„ํ•œ DOM์‚ฌ์ด์ฆˆ ํ”ผํ•˜๊ธฐ)' ํ•ญ๋ชฉ์— ํ‘œ์‹œ๋œ๋‹ค. ์ด ๋ถ€๋ถ„์—๋Š” DOM ์š”์†Œ์˜ ์ด ๊ฐœ์ˆ˜, ๊ฐ€์žฅ ๋งŽ์€ ํ•˜์œ„(children) ์š”์†Œ๋ฅผ ํฌํ•จํ•˜๋Š” DOM ์š”์†Œ ๋ฐ ๊ฐ€์žฅ ๊นŠ์€ DOM ์š”์†Œ ๋˜ํ•œ ๋ณผ ์ˆ˜ ์žˆ๋‹ค.

๋” ๊ฐ„๋‹จํ•œ ๋ฐฉ๋ฒ•์€ ์ฃผ์š” ๋ธŒ๋ผ์šฐ์ €์˜ ๊ฐœ๋ฐœ์ž ๋„๊ตฌ์—์„œ JavaScript ์ฝ˜์†”์„ ์‚ฌ์šฉํ•˜๋Š” ๊ฒƒ์ด๋‹ค. DOM์˜ ์ด HTML ์š”์†Œ์˜ ๊ฐœ์ˆ˜๋ฅผ ์–ป์œผ๋ ค๋ฉด ํŽ˜์ด์ง€๊ฐ€ ๋กœ๋“œ๋œ ํ›„ ์ฝ˜์†”์—์„œ ๋‹ค์Œ ์ฝ”๋“œ๋ฅผ ์‹คํ–‰ํ•œ๋‹ค:

  document.querySelectorAll('*').length;
  
๋ฉ”๋ชจ: ์œ„์˜ ์ฝ”๋“œ์—๋Š” DOM์˜ HTML ์š”์†Œ์˜ ๊ฐœ์ˆ˜๋งŒ ํฌํ•จ๋˜์–ด ์žˆ๋‹ค. DOM์˜ ๋ชจ๋“  ๋…ธ๋“œ๋ฅผ ํฌํ•จํ•˜์ง€๋Š” ์•Š๋Š”๋‹ค.



DOM ํฌ๊ธฐ ์—…๋ฐ์ดํŠธ๋ฅผ ์‹ค์‹œ๊ฐ„์œผ๋กœ ํ™•์ธํ•˜๋ ค๋ฉด ์„ฑ๋Šฅ ๋ชจ๋‹ˆํ„ฐ ๋„๊ตฌ๋ฅผ ์‚ฌ์šฉํ•  ์ˆ˜๋„ ์žˆ์Šต๋‹ˆ๋‹ค. ์ด ๋„๊ตฌ๋ฅผ ์‚ฌ์šฉํ•˜๋ฉด ํ˜„์žฌ DOM ํฌ๊ธฐ์™€ ํ•จ๊ป˜ ๋ ˆ์ด์•„์›ƒ ๋ฐ ์Šคํƒ€์ผ ์ž‘์—…(๊ธฐํƒ€ ์„ฑ๋Šฅ ์ธก๋ฉด)๋“ฑ์„ ์—ฐ๊ด€์‹œํ‚ฌ ์ˆ˜ ์žˆ๋‹ค.

Chrome DevTools์˜ ์„ฑ๋Šฅ ๋ชจ๋‹ˆํ„ฐ. ์—ฌ๊ธฐ์„œ๋Š” ํŽ˜์ด์ง€์˜ ํ˜„์žฌ DOM ๋…ธ๋“œ ์ˆ˜๊ฐ€ ์ดˆ๋‹น ์ˆ˜ํ–‰๋˜๋Š” ๋ ˆ์ด์•„์›ƒ ์ž‘์—…, ์Šคํƒ€์ผ ์žฌ๊ณ„์‚ฐ๊ณผ ํ•จ๊ป˜ ์ฐจํŠธ๋กœ ํ‘œ์‹œ๋ฉ๋‹ˆ๋‹ค.

 
DOM์˜ ํฌ๊ธฐ๊ฐ€ Lighthouse DOM ํฌ๊ธฐ์˜ ๊ฒฝ๊ณ  ๊ฐ’์— ์ ‘๊ทผํ•˜๊ฑฐ๋‚˜ ์‹คํŒจํ•˜๋Š” ๊ฒฝ์šฐ, ๋‹ค์Œ ๋‹จ๊ณ„๋Š” DOM์˜ ํฌ๊ธฐ๋ฅผ ์ค„์—ฌ ์›น ์‚ฌ์ดํŠธ์˜ INP๊ฐ€ ํ–ฅ์ƒ๋  ์ˆ˜ ์žˆ๋„๋ก ์‚ฌ์šฉ์ž ์ƒํ˜ธ ์ž‘์šฉ์— ์‘๋‹ตํ•˜๋Š” ํŽ˜์ด์ง€์˜ ๊ธฐ๋Šฅ์„ ํ–ฅ์ƒ์‹œํ‚ค๋Š” ๋ฐฉ๋ฒ•์„ ์ฐพ๋Š” ๊ฒƒ์ž…๋‹ˆ๋‹ค.

โ—พ๏ธ์–ด๋–ป๊ฒŒ ์ƒํ˜ธ์ž‘์šฉ์— ์˜ํ–ฅ์„ ๋ฐ›๋Š” DOM ์š”์†Œ์˜ ๊ฐœ์ˆ˜๋ฅผ  ์ธก์ •ํ• ๊นŒ?

์‹คํ—˜์‹ค์—์„œ ๋งŒ์•ฝ ๋‹น์‹ ์ด ํŽ˜์ด์ง€ DOM์˜ ํฌ๊ธฐ๊ณผ ๊ด€๋ จ๋œ ๊ฒƒ์œผ๋กœ ์˜์‹ฌ๋˜๋Š” ๋Š๋ฆฐ ์ƒํ˜ธ์ž‘์šฉ์„ ์ˆ˜์ง‘ํ•˜๋ ค ํ•œ๋‹ค๋ฉด, ๋‹น์‹ ์€ "์Šคํƒ€์ผ ์žฌ๊ณ„์‚ฐ(Recalculate Style"์ด๋ผ๋Š” ๋ ˆ์ด๋ธ”์ด ์ง€์ •๋œ ํ”„๋กœํŒŒ์ผ๋Ÿฌ์—์„œ ํ™œ๋™์„ ์„ ํƒํ•˜์—ฌ ์˜ํ–ฅ์„ ๋ฐ›์€ DOM ์š”์†Œ์˜ ๊ฐœ์ˆ˜๋ฅผ ํŒŒ์•…ํ•˜๊ณ  ์•„๋ž˜์ชฝ ํŒจ๋„์—์„œ ์ปจํ…์ŠคํŠธ ๋ฐ์ดํ„ฐ๋ฅผ ๊ด€์ฐฐํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.
 

์Šคํƒ€์ผ ์žฌ๊ณ„์‚ฐ ์ž‘์—…์˜ ๊ฒฐ๊ณผ๋กœ DOM์—์„œ ์˜ํ–ฅ์„ ๋ฐ›๋Š” ์š”์†Œ์˜ ๊ฐœ์ˆ˜๋ฅผ ๊ด€์ฐฐํ•œ๋‹ค. ์ƒํ˜ธ์ž‘์šฉ ํŠธ๋ž™์— ์žˆ๋Š” ์Œ์˜์ฒ˜๋ฆฌ๋œ ๋ถ€๋ถ„์€ ์ƒํ˜ธ ์ž‘์šฉ ์ง€์† ์‹œ๊ฐ„ ์ค‘ INP ์ง€์ •๋œ "good" ๊ฐ’์ธ 200๋ฐ€๋ฆฌ์ดˆ ์ด์ƒ์˜ ๋ถ€๋ถ„์„ ๋‚˜ํƒ€๋‚ธ๋‹ค.

 
์œ„ ์Šคํฌ๋ฆฐ์ƒท์—์„œ ์ž‘์—…์˜ ์Šคํƒ€์ผ ์žฌ๊ณ„์‚ฐ(์„ ํƒ ์‹œ)์— ์˜ํ–ฅ์„ ๋ฐ›๋Š” ์š”์†Œ์˜ ๊ฐœ์ˆ˜๊ฐ€ ํ‘œ์‹œ๋˜๋Š”์ง€ ํ™•์ธํ•œ๋‹ค. ์œ„ ์Šคํฌ๋ฆฐ์ƒท์€ ๋งŽ์€ DOM ์š”์†Œ๊ฐ€ ์žˆ๋Š” ํŽ˜์ด์ง€์˜ ๋ Œ๋”๋ง ์ž‘์—…์— DOM ํฌ๊ธฐ๊ฐ€ ๋ฏธ์น˜๋Š” ์˜ํ–ฅ์˜ ๊ทน๋‹จ์ ์ธ ๊ฒฝ์šฐ๋ฅผ ๋ณด์—ฌ์ฃผ์ง€๋งŒ, ์ด ์ •๋ณด๋Š” ์–ด๋–ค ๊ฒฝ์šฐ์—๋„ DOM ํฌ๊ธฐ๊ฐ€ ์ƒํ˜ธ ์ž‘์šฉ์— ์‘๋‹ตํ•˜์—ฌ ๋‹ค์Œ ํ”„๋ ˆ์ž„์„ ๊ทธ๋ฆฌ๋Š” ๋ฐ ๊ฑธ๋ฆฌ๋Š” ์‹œ๊ฐ„์— ํ•œ๊ณ„ ์š”์†Œ์ธ์ง€ ํŒ๋‹จํ•˜๋Š” ๋ฐ์— ์œ ์šฉํ•˜๋‹ค.
 

โ—พ๏ธ์–ด๋–ป๊ฒŒ DOM ์‚ฌ์ด์ฆˆ๋ฅผ ์ค„์ผ๊นŒ?

๋ถˆํ•„์š”ํ•œ ๋งˆํฌ์—…์„ ์œ„ํ•ด ์›น์‚ฌ์ดํŠธ์˜ HTML์„ ๊ฐ์‚ฌํ•˜๋Š” ๊ฒƒ ์™ธ์—๋„ DOM ํฌ๊ธฐ๋ฅผ ์ค„์ด๋Š” ์ฃผ์š” ๋ฐฉ๋ฒ•์€ DOM ๊นŠ์ด๋ฅผ ์ค„์ด๋Š” ๊ฒƒ์ด๋‹ค. DOM์ด ๋ถˆํ•„์š”ํ•˜๊ฒŒ ๊นŠ์„ ์ˆ˜ ์žˆ๋‹ค๋Š” ์‹ ํ˜ธ ์ค‘์˜ ํ•˜๋‚˜๋Š” ๋ธŒ๋ผ์šฐ์ € ๊ฐœ๋ฐœ์ž ๋„๊ตฌ์˜ ์š”์†Œ ํƒญ์—์„œ ๋‹ค์Œ๊ณผ ๊ฐ™์€ ๋งˆํฌ์—…์ด ๋ณด์ด๋Š” ์‹ ํ˜ธ์ด๋‹ค.
 

    <div>
      <div>
        <div>
          <div>
            <!-- Contents -->
          </div>
        </div>
      </div>
    </div>

 
์ด์™€ ๊ฐ™์€ ํŒจํ„ด์„ ๋ณด๋ฉด ์•„๋งˆ๋„ DOM ๊ตฌ์กฐ๋ฅผ ํ‰ํ‰ํ•˜๊ฒŒ ํ•˜์—ฌ ํŒจํ„ด์„ ๋‹จ์ˆœํ™”ํ•  ์ˆ˜ ์žˆ๋‹ค. ๊ทธ๋ ‡๊ฒŒ ํ•˜๋ฉด DOM ์š”์†Œ์˜ ๊ฐœ์ˆ˜๊ฐ€ ์ค„์–ด๋“ค๊ณ  ํŽ˜์ด์ง€ ์Šคํƒ€์ผ์„ ๋‹จ์ˆœํ™”ํ•  ์ˆ˜ ์žˆ๋Š” ๊ธฐํšŒ๊ฐ€ ์ฃผ์–ด์ง„๋‹ค.
 
DOM์˜ ๊นŠ์ด๋Š” ์‚ฌ์šฉํ•˜๋Š” ํ”„๋ ˆ์ž„์›Œํฌ์˜ ์ฆ์ƒ์ผ ์ˆ˜๋„ ์žˆ๋‹ค. ํŠนํžˆ JSX์— ์˜์กดํ•˜๋Š” ๊ฒƒ๊ณผ ๊ฐ™์€ ๊ตฌ์„ฑ ์š”์†Œ ๊ธฐ๋ฐ˜ ํ”„๋ ˆ์ž„์›Œํฌ์—์„œ๋Š” ์ƒ์œ„ ์ปจํ…Œ์ด๋„ˆ์— ์—ฌ๋Ÿฌ ๊ตฌ์„ฑ ์š”์†Œ๋ฅผ ์ค‘์ฒฉํ•ด์•ผ ํ•œ๋‹ค.
 
๊ทธ๋Ÿฌ๋‚˜ ๋งŽ์€ ํ”„๋ ˆ์ž„์›Œํฌ์—์„œ๋Š” fragment๋ผ๊ณ  ์•Œ๋ ค์ง„ ๊ฒƒ์„ ์‚ฌ์šฉํ•˜์—ฌ nesting ๊ตฌ์„ฑ ์š”์†Œ๋ฅผ ํ”ผํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. fragment๋ฅผ ๊ธฐ๋Šฅ์œผ๋กœ ์ œ๊ณตํ•˜๋Š” ๊ตฌ์„ฑ ์š”์†Œ ๊ธฐ๋ฐ˜ ํ”„๋ ˆ์ž„์›Œํฌ์—๋Š” ๋‹ค์Œ๊ณผ ๊ฐ™์€ ๊ฒƒ์ด ์žˆ๋‹ค(๊ทธ๋Ÿฌ๋‚˜ ์ด์— ๊ตญํ•œ๋˜์ง€๋Š” ์•Š๋‹ค):
 


์„ ํƒํ•œ ํ”„๋ ˆ์ž„์›Œํฌ์— fragments์„ ์‚ฌ์šฉํ•˜๋ฉด DOM ๊นŠ์ด๋ฅผ ์ค„์ผ ์ˆ˜ ์žˆ๋‹ค. DOM ๊ตฌ์กฐ๋ฅผ ํ‰ํ‰ํ•˜๊ฒŒ ๋งŒ๋“œ๋Š” ๊ฒƒ์ด ์Šคํƒ€์ผ๋ง์— ์˜ํ–ฅ์„ ๋ฏธ์น˜๋Š” ์ ์ด ๊ฑฑ์ •๋œ๋‹ค๋ฉด ํ”Œ๋ ‰์Šค๋ฐ•์Šค(flexbox) ๋˜๋Š” ๊ทธ๋ฆฌ๋“œ(grid)์™€ ๊ฐ™์€ ๋ณด๋‹ค ํ˜„๋Œ€์ ์ธ(๋ฐ ๋” ๋น ๋ฅธ) ๋ ˆ์ด์•„์›ƒ ๋ชจ๋“œ๋ฅผ ์‚ฌ์šฉํ•˜๋ฉด ์ด์ ์„ ์–ป์„ ์ˆ˜ ์žˆ์„ ๊ฒƒ์ด๋‹ค.

โ—พ๏ธ๊ธฐํƒ€ ๊ณ ๋ คํ•ด์•ผ ํ•  ์ „๋žต

 

DOM ํŠธ๋ฆฌ๋ฅผ ํ‰ํ‰ํ•˜๊ฒŒ ํ•˜๊ณ  ๋ถˆํ•„์š”ํ•œ HTML ์š”์†Œ๋ฅผ ์ œ๊ฑฐํ•˜์—ฌ DOM์„ ์ตœ๋Œ€ํ•œ ์ž‘๊ฒŒ ์œ ์ง€ํ•˜๋”๋ผ๋„ ์‚ฌ์šฉ์ž์˜ ์ƒํ˜ธ ์ž‘์šฉ์— ๋”ฐ๋ผ์„œ ๋ณ€๊ฒฝ๋  ์ˆ˜ ์žˆ์–ด ์—ฌ์ „ํžˆ ๊ฝค ํฐ ๋ Œ๋”๋ง ์ž‘์—…์ด ์‹œ์ž‘๋  ์ˆ˜ ์žˆ๋‹ค. ์ด๋Ÿฌํ•œ ์œ„์น˜์— ์žˆ๋‹ค๋ฉด ๋ Œ๋”๋ง ์ž‘์—…์„ ์ œํ•œํ•˜๊ธฐ ์œ„ํ•ด ๊ณ ๋ คํ•  ์ˆ˜ ์žˆ๋Š” ๋‹ค๋ฅธ ์ „๋žต์ด ์žˆ๋‹ค.
 
- ์ถ”๊ฐ€์ ์ธ ์ ‘๊ทผ๋ฒ•
ํŽ˜์ด์ง€๊ฐ€ ์ฒ˜์Œ ๋ Œ๋”๋ง๋  ๋•Œ ์ฒ˜์Œ์— ํŽ˜์ด์ง€์˜ ๋งŽ์€ ๋ถ€๋ถ„์ด ์‚ฌ์šฉ์ž์—๊ฒŒ ๋ณด์ด์ง€ ์•Š๋Š” ์œ„์น˜์— ์žˆ์„ ์ˆ˜ ์žˆ๋‹ค. ์ด๋Š” ์‹œ์ž‘ ์‹œ DOM์˜ ํ•ด๋‹น ๋ถ€๋ถ„์„ ์ƒ๋žตํ•˜์—ฌ HTML์„ ๋Š๋ฆฌ๊ฒŒ ๋กœ๋“œํ•˜์ง€๋งŒ, ์‚ฌ์šฉ์ž๊ฐ€ ํŽ˜์ด์ง€์—์„œ ์ดˆ๊ธฐ์— ์ˆจ๊ฒจ์ง„ ์ธก๋ฉด์„ ํŽ˜์ด์ง€์—์„œ ํ•„์š”ํ•œ ๋ถ€๋ถ„๊ณผ ์ƒํ˜ธ ์ž‘์šฉํ•  ๋•Œ ์ถ”๊ฐ€๋  ์ˆ˜ ์žˆ๊ธฐ๋„ ํ•˜๋‹ค.

์ด ์ ‘๊ทผ ๋ฐฉ์‹์€ ์ดˆ๊ธฐ์— ๋กœ๋“œ๋  ๋•Œ์™€ ์•„๋งˆ๋„ ์ดํ›„์—๋„ ์œ ์šฉํ•˜๋‹ค. ์ดˆ๊ธฐ ํŽ˜์ด์ง€ ๋กœ๋“œ์˜ ๊ฒฝ์šฐ, ๋” ์ ์€ ๋ Œ๋”๋ง ์ž‘์—…์„ ์•ž์—์„œ ์ˆ˜ํ–‰ํ•˜๊ฒŒ ๋œ๋‹ค. ์ฆ‰, ์ดˆ๊ธฐ HTML ํŽ˜์ด๋กœ๋“œ๊ฐ€ ๋” ๊ฐ€๋ฒผ์›Œ์ง€๊ณ  ๋” ๋นจ๋ฆฌ ๋ Œ๋”๋ง๋œ๋‹ค. ์ด๋Š” ์ค‘์š”ํ•œ ๊ธฐ๊ฐ„ ๋™์•ˆ ๋ฉ”์ธ ์Šค๋ ˆ๋“œ์˜ ๊ด€์‹ฌ์„ ๋Œ๊ธฐ ์œ„ํ•ด ๊ฒฝ์Ÿ์„ ๋œ ํ•˜๋ฉด์„œ ์‹คํ–‰ํ•  ์ˆ˜ ์žˆ๋Š” ๋” ๋งŽ์€ ๊ธฐํšŒ๋ฅผ ์ œ๊ณตํ•  ๊ฒƒ์ด๋‹ค.

๋งŒ์•ฝ ํŽ˜์ด์ง€ ์ดˆ๊ธฐ ๋กœ๋“œ์‹œ์˜ ์ˆจ๊ฒจ์ง„ ๋ถ€๋ถ„์ด ๋งŽ๋‹ค๋ฉด ๋ฆฌ๋ Œ๋”๋ง ์ž‘์—…์„ ์œ ๋ฐœํ•˜๋Š” ๋‹ค๋ฅธ ์ƒํ˜ธ์ž‘์šฉ๋“ค์˜ ์†๋„๋ฅผ ๋†’์ผ ์ˆ˜ ์žˆ๋‹ค. ๊ทธ๋Ÿฌ๋‚˜ ๋‹ค๋ฅธ ์ƒํ˜ธ ์ž‘์šฉ์ด DOM์— ์ถ”๊ฐ€๋จ์— ๋”ฐ๋ผ ํŽ˜์ด์ง€ ์ˆ˜๋ช… ์ฃผ๊ธฐ ์ „๋ฐ˜์— ๊ฑธ์ณ DOM์ด ์ฆ๊ฐ€ํ•˜๋ฉฐ ๋ Œ๋”๋ง ์ž‘์—…์ด ์ฆ๊ฐ€ํ•œ๋‹ค.

์‹œ๊ฐ„์ด ์ง€๋‚˜๋ฉด์„œ DOM์„ ์ถ”๊ฐ€ํ•˜๋Š” ๊ฒƒ์€ ๊นŒ๋‹ค๋กœ์šธ ์ˆ˜ ์žˆ์œผ๋ฉฐ ๊ณ ์œ ํ•œ ์ ˆ์ถฉ์ ์ด ์žˆ๋‹ค. ์ด ๊ฒฝ์šฐ์—๋Š” ์‚ฌ์šฉ์ž ์ƒํ˜ธ ์ž‘์šฉ์— ๋Œ€ํ•œ ์‘๋‹ต์œผ๋กœ ํŽ˜์ด์ง€์— ์ถ”๊ฐ€ํ•˜๋ ค๋Š” HTML์„ ์ฑ„์šฐ๊ธฐ ์œ„ํ•œ ๋ฐ์ดํ„ฐ๋ฅผ ์–ป๊ธฐ ์œ„ํ•ด ๋„คํŠธ์›Œํฌ ์š”์ฒญ์„ ํ•  ๊ฐ€๋Šฅ์„ฑ์ด ๋†’๋‹ค. ์ค‘๊ฐ„ ๋„คํŠธ์›Œํฌ ์š”์ฒญ์€ INP์— ํฌํ•จ๋˜์ง€ ์•Š์ง€๋งŒ ์ธ์ง€๋œ ์ง€์—ฐ ์‹œ๊ฐ„์„ ์ฆ๊ฐ€์‹œํ‚ฌ ์ˆ˜ ์žˆ๋‹ค. ๊ฐ€๋Šฅํ•œ ๊ฒฝ์šฐ ๋กœ๋”ฉ ์Šคํ”ผ๋„ˆ ๋˜๋Š” ๋ฐ์ดํ„ฐ๋ฅผ ๊ฐ€์ ธ์˜ค๋Š” ์ค‘์ž„์„ ํ‘œ์‹œํ•ด ์‚ฌ์šฉ์ž๊ฐ€ ๋ฌด์–ธ๊ฐ€๊ฐ€ ๋ฐœ์ƒํ•˜๊ณ  ์žˆ์Œ์„ ์•Œ๋„๋ก ํ•œ๋‹ค.

โ—พ๏ธCSS ์…€๋ ‰ํ„ฐ์˜ ๋ณต์žก์„ฑ ์ œํ•œ


๋ธŒ๋ผ์šฐ์ €๊ฐ€ CSS์˜ ์…€๋ ‰ํ„ฐ๋ฅผ ํŒŒ์‹ฑํ•  ๋•Œ ํ•ด๋‹น ์…€๋ ‰ํ„ฐ๊ฐ€ ํ˜„์žฌ ๋ ˆ์ด์•„์›ƒ์— ์ ์šฉ๋˜๋Š” ๋ฐฉ๋ฒ•๊ณผ ์ ์šฉ๋˜๋Š” ๊ฒฝ์šฐ๋ฅผ ์•Œ๋ ค๋ฉด DOM ํŠธ๋ฆฌ๋ฅผ ํšก๋‹จํ•ด์•ผ ํ•œ๋‹ค. ์ด๋Ÿฌํ•œ css ์…€๋ ‰ํ„ฐ๋“ค์ด ๋ณต์žกํ• ์ˆ˜๋ก, ๋ธŒ๋ผ์šฐ์ €๋Š” ํŽ˜์ด์ง€์˜ ์ดˆ๊ธฐ ๋ Œ๋”๋ง๋ฟ๋งŒ ์•„๋‹ˆ๋ผ, ์ƒํ˜ธ์ž‘์šฉ์˜ ๊ฒฐ๊ณผ๋กœ ํŽ˜์ด์ง€๊ฐ€ ๋ณ€๊ฒฝ๋˜๋Š” ๊ฒฝ์šฐ ์Šคํƒ€์ผ ์žฌ๊ณ„์‚ฐ ๋ฐ ๋ ˆ์ด์•„์›ƒ ์ž‘์—…์„ ์ฆ๊ฐ€์‹œํ‚ค๊ธฐ ์œ„ํ•ด ๋” ๋งŽ์€ ์ž‘์—…์„ ์ˆ˜ํ–‰ํ•ด์•ผ ํ•œ๋‹ค.

๋” ์•Œ์•„๋ณด๊ธฐ: ์Šคํƒ€์ผ ๊ณ„์‚ฐ์˜ ๋ณต์žก์„ฑ๊ณผ ์Šค์ฝ”ํ”„ ์ค„์ด๊ธฐ


โ—พ๏ธ content-visibility ํ”„๋กœํผํ‹ฐ๋ฅผ ์‚ฌ์šฉํ•˜๋ผ

CSS๋Š” ํ™”๋ฉด ๋ฐ– DOM์š”์†Œ๋ฅผ ๋Š๊ธ‹ํ•˜๊ฒŒ ๋ Œ๋”๋งํ•  ์ˆ˜ ์žˆ๋Š” ํšจ๊ณผ์ ์ธ ๋ฐฉ๋ฒ•์ธ content-visibility ํ”„๋กœํผํ‹ฐ๋ฅผ ์ œ๊ณตํ•œ๋‹ค. ์š”์†Œ๋“ค์ด ๋ทฐํฌํŠธ์— ์ ‘๊ทผํ•˜๋ฉด ํ•„์š”์— ๋”ฐ๋ผ ๋ Œ๋”๋ง๋œ๋‹ค. content-visibility์˜ ์ด์ ์€ ์ดˆ๊ธฐ ํŽ˜์ด์ง€ ๋ Œ๋”๋ง์‹œ ์ƒ๋‹นํ•œ ์–‘์˜ ๋ Œ๋”๋ง ์ž‘์—…์„ ์ค„์—ฌ์ค„ ๋ฟ๋งŒ ์•„๋‹ˆ๋ผ ์‚ฌ์šฉ์ž์˜ ์ƒํ˜ธ์ž‘์šฉ์œผ๋กœ ํŽ˜์ด์ง€ DOM์ด ๋ณ€๊ฒฝ๋  ๋•Œ ์˜คํ”„์Šคํฌ๋ฆฐ ์š”์†Œ ๋ Œ๋”๋ง ์ž‘์—…์„ ์ƒ๋žตํ•  ์ˆ˜ ์žˆ๋‹ค๋Š” ๊ฒƒ์ด๋‹ค.

 

 ๋” ์•Œ์•„๋ณด๊ธฐ: content-visibility: ๋ Œ๋”๋ง ํผํฌ๋จผ์Šค๋ฅผ ์˜ฌ๋ ค์ฃผ๋Š” ์ƒˆ๋กœ์šด CSS ํ”„๋กœํผํ‹ฐ

 

 

๐ŸŒŸ  ๊ฒฐ๋ก 

DOM ์‚ฌ์ด์ฆˆ๋ฅผ ํ•„์š”ํ•œ๊ฒƒ์œผ๋กœ๋งŒ ์ค„์ด๋Š” ๊ฒƒ์ด ๋‹น์‹ ์˜ ์›น์‚ฌ์ดํŠธ์˜ INP๋ฅผ ์ตœ์ ํ™”ํ•˜๋Š” ์ข‹์€ ๋ฐฉ๋ฒ•์ด๋‹ค. ์ด๋ ‡๊ฒŒ ํ•˜๋ฉด DOM์ด ์—…๋ฐ์ดํŠธ๋  ๋•Œ ๋ธŒ๋ผ์šฐ์ €๊ฐ€ ๋ ˆ์ด์•„์›ƒ ๋ฐ ๋ Œ๋”๋ง ์ž‘์—…์„ ์ˆ˜ํ–‰ํ•˜๋Š” ๋ฐ ๊ฑธ๋ฆฌ๋Š” ์‹œ๊ฐ„์„ ์ค„์ผ ์ˆ˜ ์žˆ๋‹ค. ๋‹น์‹ ์ด DOM ํฌ๊ธฐ๋ฅผ ์˜๋ฏธ ์žˆ๊ฒŒ ์ค„์ผ ์ˆ˜ ์—†๋”๋ผ๋„ ๋ Œ๋”๋ง ์ž‘์—…์„ DOM ํ•˜์œ„ ํŠธ๋ฆฌ๋กœ ๊ฒฉ๋ฆฌํ•˜๋Š” ๋ฐ ์‚ฌ์šฉํ•˜๋Š” CSS containment ๋ฐ content-visibility ํ”„๋กœํผํ‹ฐ ๊ฐ™์€ ๋ช‡ ๊ฐ€์ง€ ๊ธฐ์ˆ ์ด ์žˆ๋‹ค.

 

๊ทธ๋Ÿฌ๋‚˜ ๋ Œ๋”๋ง ์ž‘์—…์„ ์ตœ์†Œํ™”ํ•  ์ˆ˜ ์žˆ๋Š” ํ™˜๊ฒฝ์„ ๋งŒ๋“ค๊ณ  ํŽ˜์ด์ง€๊ฐ€ ์ƒํ˜ธ ์ž‘์šฉ์— ๋ฐ˜์‘ํ•ด ์ˆ˜ํ–‰ํ•˜๋Š” ๋ Œ๋”๋ง ์ž‘์—…์˜ ์–‘์„ ์ค„์ด๋ฉด ์›น ์‚ฌ์ดํŠธ๊ฐ€ ์‚ฌ์šฉ์ž์™€ ์ƒํ˜ธ ์ž‘์šฉํ•  ๋•Œ ๋” ์ž˜ ๋ฐ˜์‘ํ•œ๋‹ค๊ณ  ๋Š๋‚„ ์ˆ˜ ์žˆ๋‹ค. ์ฆ‰, ์›น ์‚ฌ์ดํŠธ์— ๋Œ€ํ•œ INP๊ฐ€ ๋‚ฎ์•„์ง€๊ณ  ์‚ฌ์šฉ์ž ๊ฒฝํ—˜์ด ํ–ฅ์ƒ๋œ๋‹ค.

๐Ÿ—ฃ๏ธ ์ด ๊ธ€์€ ์•„๋ž˜ ๊ธ€์˜ ๋ฒˆ์—ญ๊ธ€์ž…๋‹ˆ๋‹ค.

 

https://blog.logrocket.com/typescript-vs-flow-vs-proptypes/

 

Comparing statically typed JavaScript implementations - LogRocket Blog

In this post, we'll compare three of the most popular ways of imposing static typing on JavaScript: TypeScript, Flow, and PropTypes.

blog.logrocket.com

 

์ž๋ฐ”์Šคํฌ๋ฆฝํŠธ๋Š” ๋ณ€์ˆ˜์˜ ๋ฐ์ดํ„ฐ ํƒ€์ž…์ด ๋Ÿฐํƒ€์ž„ ํ™˜๊ฒฝ์—์„œ ๊ทธ ๋ณ€์ˆ˜์— ์˜ํ•ด ๊ฒฐ์ •๋˜๊ณ , ํ”„๋กœ๊ทธ๋žจ์„ ํ†ตํ•ด ์šฐ๋ฆฌ๊ฐ€ ๋‹ค๋ฅธ ๊ฐ’์œผ๋กœ ๊ทธ ๋ณ€์ˆ˜์— ํ• ๋‹นํ•  ๊ฒฝ์šฐ์—๋„ ๋ณ€ํ•  ์ˆ˜ ์žˆ๋Š” ๋™์  ํƒ€์ž… ์–ธ์–ด(Dynamically typed language)์ด๋‹ค.

 

์ž๋ฐ”์Šคํฌ๋ฆฝํŠธ์—๋Š” ๋ณ€์ˆ˜์˜ ํƒ€์ž…์„ ์ œํ•œํ•˜๊ฑฐ๋‚˜ ์ฃผ์„ ์ฒ˜๋ฆฌํ•  ๋ฐฉ๋ฒ•์ด ๋‚ด์žฅ๋˜์–ด ์žˆ์ง€ ์•Š๋‹ค. ์šฐ๋ฆฌ๊ฐ€ ํ”„๋กœ๊ทธ๋žจ์„ ์ž‘์„ฑํ• ๋•Œ ๋ณ€์ˆ˜๊ฐ€ ๊ฐ€์ ธ์•ผ ํ•˜๋Š” ํƒ€์ž…์— ๋Œ€ํ•ด ๊ณ ๋ฏผ์„ ๋งŽ์ด ํ•˜๋Š” ๊ฒƒ์„ ๋œ์–ด์ฃผ๊ณ  ์กฐ๊ธˆ ๋” ๋น ๋ฅด๊ฒŒ ์ž‘์„ฑํ•  ์ˆ˜ ์žˆ๊ฒŒ ํ•ด์ฃผ์ง€๋งŒ, ์ด ๋ง์€ ๋˜ํ•œ ์šฐ๋ฆฌ์˜ ํ”„๋กœ๊ทธ๋žจ์ด ๋ฒ„๊ทธ๋ฅผ ๊ฐ–๊ฑฐ๋‚˜ ๋ณ€์ˆ˜๊ฐ€ ๋‹ค๋ฅธ ํƒ€์ž…์ด ๋˜์–ด ์˜ˆ๊ธฐ์น˜ ๋ชปํ•œ ํ–‰๋™์„ ์œ ๋ฐœํ•  ์ˆ˜๋„ ์žˆ๋‹ค๋Š” ๋œป์ด๊ธฐ๋„ ํ•˜๋‹ค.

 

์ž๋ฐ”์Šคํฌ๋ฆฝํŠธ์˜ ์ด๋Ÿฌํ•œ ๋™์  ํƒ€์ดํ•‘์˜ ๋ฌธ์ œ๋ฅผ ํ”ผํ•˜๊ธฐ ์œ„ํ•ด ์šฐ๋ฆฌ๋Š” ํ”„๋กœ๊ทธ๋žจ์„ ๋‹ค๋ฅธ ์–ธ์–ด๋กœ ์ž‘์„ฑํ•˜๊ณ  ์ž๋ฐ”์Šคํฌ๋ฆฝํŠธ๋กœ ํŠธ๋žœ์ŠคํŒŒ์ผ ํ•ด์•ผ ํ•œ๋‹ค. ์ด๋ฅผ ์œ„ํ•ด ๋ณ€์ˆ˜๋ฅผ ์—„๊ฒฉํ•˜๊ฒŒ ํ™•์ธํ•˜๊ณ  ์ œ์–ดํ•˜๋Š” ์ž๋ฐ”์Šคํฌ๋ฆฝํŠธ์˜ ํƒ€์ž… ์ต์Šคํ…์…˜์ด ํ•„์š”ํ•˜๋‹ค.

 

์—ฌ๊ธฐ ์ž๋ฐ”์Šคํฌ๋ฆฝํŠธ์˜ ์ •์  ํƒ€์ž… ์ต์Šคํ…์…˜์„ ์ œ๊ณตํ•˜๋Š” ๋งŽ์€ ์–ธ์–ด๋“ค์ด ์žˆ๋‹ค.

 

์ด ๊ธ€์€ ํƒ€์ž…์Šคํฌ๋ฆฝํŠธ, Flow, Prop Types์— ์ดˆ์ ์„ ๋งž์ถ”๊ณ  ์ด ์–ธ์–ด๋“ค์˜ ๊ธฐ๋Šฅ๊ณผ ๋Šฅ๋ ฅ์„ ๋น„๊ตํ•œ๋‹ค.

 

โœฃ Type-Checkiing ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ / ์–ธ์–ด ๋น„๊ตํ•˜๊ธฐ

  Typescript Flow Prop Types
๊ฐœ๋ฐœ์ž Microsoft Facebook Facebook
๋ฆด๋ฆฌ์ฆˆ 2012.10.1 2014.11.18 2017.4.8
๋ผ์ด์„ผ์Šค ์˜คํ”ˆ์†Œ์Šค MIT MIT
์ปค๋ฎค๋‹ˆํ‹ฐ ํผ ์ž‘์Œ ์ƒ๋Œ€์ ์œผ๋กœ ์ž‘์Œ
Dependencies
Performace ๊ฐ€์žฅ ๋น ๋ฅด๊ณ  ๋ฒ„๊ทธ๊ฐ€ ์ ๋‹ค ์ผ๋ถ€ ๋ฉ”๋ชจ๋ฆฌ ๋ˆ„์ˆ˜ ๋ณด๊ณ ๋จ. Flow ํŒ€์€ 2019๋…„์— ์žฌ๊ฒ€์‚ฌ ์‹œ๊ฐ„๊ณผ ๋ฉ”๋ชจ๋ฆฌ ์‚ฌ์šฉ๋Ÿ‰์ด ๊ฐ์†Œํ–ˆ๋‹ค๊ณ  ๋ณด๊ณ ํ–ˆ์Šต๋‹ˆ๋‹ค. ๋ณด๊ณ ๋˜์ง€ ์•Š์€ ์„ฑ๋Šฅ ํ†ต๊ณ„
ํƒ€์ž… ์ฒดํฌ
(type checking)
์ž๋ฐ”์Šคํฌ๋ฆฝํŠธ ํƒ€์ž…, ์ œ๋„ค๋ฆญ ํƒ€์ž… ์ •์˜, ์„ ํƒ์  nullable ํƒ€์ž… ์‚ฌ์šฉ ์•„๋งˆ๋„ ์ž๋ฐ”์Šคํฌ๋ฆฝํŠธ ํƒ€์ž…, ์ œ๋„ค๋ฆญ ํƒ€์ž… ์ •์˜, ์„ ํƒ์  nullable ํƒ€์ž… ์‚ฌ์šฉ ์ž์ฒด ํƒ€์ž… ์œ ํšจ์„ฑ ๊ฐ์ฒด ์‚ฌ์šฉ
ํƒ€์ž… ์บ์ŠคํŒ…
(type casting)
as ํ‚ค์›Œ๋“œ ์‚ฌ์šฉ : ์‹ฌ๋ณผ ์‚ฌ์šฉ N/A
interfaces, enums, ์ปค์Šคํ…€ ํƒ€์ž… ๊ฐ์ฒด ์ง€์› interfaces, enums, ์ปค์Šคํ…€ ํƒ€์ž… ๊ฐ์ฒด ์ง€์› interfaces, enums, ์ธํ„ฐํŽ˜์ด์Šค์™€ enum์œผ๋กœ ํ‚ค์›Œ๋“œ ์„ ์–ธ๋จ ์ž์ฒด ์˜ต์…˜์„ ์‚ฌ์šฉํ•œ enum, PropTyps.oneOf([...]) ์ง€์›
ํ…์ŠคํŠธ ์—๋””ํ„ฐ ์ง€์› IntelliSense(์ž๋™ ์™„์„ฑ), ์ •์˜๋กœ ์ด๋™, ์˜ค๋ฅ˜/๊ฒฝ๊ณ  ๋“ฑ๊ณผ ๊ฐ™์€ ๊ธฐ๋Šฅ์„ ์ œ๊ณตํ•˜๋Š” ์—ฌ๋Ÿฌ ํŽธ์ง‘๊ธฐ/IDE์— ๋Œ€ํ•œ ๋Œ€๊ทœ๋ชจ ์ง€์› IntelliSense(์ž๋™ ์™„์„ฑ), ์ •์˜๋กœ ์ด๋™, ์˜ค๋ฅ˜/๊ฒฝ๊ณ  ๋“ฑ๊ณผ ๊ฐ™์€ ๊ธฐ๋Šฅ์„ ์ œ๊ณตํ•˜๋Š” ์—ฌ๋Ÿฌ ํŽธ์ง‘๊ธฐ/IDE์— ๋Œ€ํ•œ ๋Œ€๊ทœ๋ชจ ์ง€์› ์ปดํฌ๋„ŒํŠธ propTypes์„ ์ž๋™ ์ƒ์„ฑํ•˜๊ธฐ ์œ„ํ•œ Visual studio code, Webstorm์˜ ์ œํ•œ๋œ ์ง€์›
Resources and Documentation
์ปค๋ฎคํ‹ฐ๋‹ˆ์™€ ํ”„๋กœ์ ํŠธ ์ง€์› Nest.js๋ฅผ ํฌํ•จํ•˜์—ฌ Vue, React, Angular, Express ๋“ฑ ์ฆ‰์‹œ ์‚ฌ์šฉ ๊ฐ€๋Šฅํ•œ ์—ฌ๋Ÿฌ ํ”„๋ ˆ์ž„์›Œํฌ ๋ฐ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ์—์„œ ์ง€์› ๋ฐ”๋ฒจ์„ ํ†ตํ•ด ํ”„๋กœ์ ํŠธ์— ์„ค์น˜ ๊ฐ€๋Šฅ, ๊ฐ€์žฅ ์ผ๋ฐ˜์ ์œผ๋กœ React์™€ ์‚ฌ์šฉ ์ฃผ๋กœ React์™€ ์‚ฌ์šฉ๋˜์ง€๋งŒ PropTypes.checkPropTypes๋ฅผ ํ˜ธ์ถœํ•ด ๋‹ค๋ฅธ ํ”„๋ ˆ์ž„์›Œํฌ์™€ ์‚ฌ์šฉ๊ฐ€๋Šฅ
์ปดํŒŒ์ผ๋Ÿฌ ์—๋Ÿฌ ๊ฐ์ง€ IDE์™€ ํ…์ŠคํŠธ์—๋””ํ„ฐ์—์„œ ๊ฐ€๋Šฅ ์ง€์›๋˜๋Š” IDE์™€ ํ…์ŠคํŠธ์—๋””ํ„ฐ์—์„œ ๊ฐ€๋Šฅ ์‚ฌ์šฉ ๋ถˆ๊ฐ€
Syntax ๊ด‘๋ฒ”์œ„ํ•œ ํƒ€์ž… ์ฒดํ‚น, ์ •์  ๋™์  ํƒ€์ž… ํฌํ•จ ๊ด‘๋ฒ”์œ„ํ•œ ํƒ€์ž… ์ฒดํ‚น, ์ •์  ๋™์  ํƒ€์ž… ํฌํ•จ PropTypes ๊ฐ์ฒด๋ฅผ ์ฐธ์กฐํ•œ ์˜์กด
์ œ๋„ˆ๋ฆญ(Generics) ์ง€์›๋จ ์ง€์›๋จ ์ง€์› ์•ˆ ๋จ
๊ธฐ์กด ํ”„๋กœ์ ํŠธ ์ง€์› ํƒ€์ž…์Šคํฌ๋ฆฝํŠธ๋Š” ํƒ€์ž…์Šคํฌ๋ฆฝํŠธ๋ฅผ ์ง€์›ํ•˜๊ธฐ ์œ„ํ•ด ์ถ”๊ฐ€ ๊ฐ€๋Šฅ ๋ฐ”๋ฒจ๊ณผ ํ•จ๊ป˜ ์ง€์› ๊ฐ€๋Šฅ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ ์„ค์น˜์™€ PropTypes.checkPropTypes ์ˆ˜๋™ ํ˜ธ์ถœ์„ ํ†ตํ•ด ์ง€์›

 

 

์ด ๊ธ€์—์„œ๋Š” ์ด๋Ÿฌํ•œ ์ž๋ฐ”์Šคํฌ๋ฆฝํŠธ ํ™•์žฅ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ/์–ธ์–ด์˜ ๊ธฐ์ˆ ๊ณผ ๋Šฅ๋ ฅ์„ ๋น„๊ตํ•˜๊ณ  ๋Œ€์กฐํ•  ๊ฒƒ์ด๋‹ค.

 

์œ ์‚ฌ์ ๊ณผ ์ฐจ์ด์ ์„ ํƒ์ƒ‰ํ•  ๋•Œ ๋จผ์ € ์ฃผ๋ชฉํ•ด์•ผ ํ•  ์ค‘์š”ํ•œ ์ฐจ์ด์ ์€ TypeScript์™€ ๋‹ฌ๋ฆฌ Flow ๋ฐ PropTypes๋Š” ํ”„๋กœ๊ทธ๋ž˜๋ฐ ์–ธ์–ด๊ฐ€ ์•„๋‹ˆ๋ผ๋Š” ๊ฒƒ์ด๋‹ค. Flow์™€ Prop Types๋Š” ์˜ค์ง ์ •์  ํƒ€์ž… ์ฒดํ‚น ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ์ด๋ฉฐ ์ฐจ์ด์ ์€ ํ•ด๋‹น ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ์˜ ์‚ฌ์šฉ์„ ์ง€์›ํ•˜๋Š” ํ”„๋ ˆ์ž„์›Œํฌ์— ์˜ํ–ฅ์„ ๋ฏธ์นœ๋‹ค.

 

โš™๏ธ ํ”„๋กœ์ ํŠธ์— ํƒ€์ž…์Šคํฌ๋ฆฝํŠธ ์„ค์น˜ํ•˜๊ธฐ

ํƒ€์ž…์Šคํฌ๋ฆฝํŠธ๋Š” ์ด ๊ธ€์—์„œ ๋น„๊ตํ•œ ์„ธ ๊ฐ€์ง€ ๊ธฐ์ˆ ์ค‘ ๊ฐ€์žฅ ๋งŽ์€ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ๋ฅผ ์ œ๊ณตํ•˜๋ฉฐ Vue, Angular ๋˜๋Š” React์—์„œ ์ฆ‰์‹œ ํƒ€์ž…์Šคํฌ๋ฆฝํŠธ๋ฅผ ์‚ฌ์šฉํ•˜๋Š” ๊ฒƒ์ด ์‰ฝ๋‹ค.

 

์˜ˆ๋ฅผ ๋“ค์–ด, ์šฐ๋ฆฌ๋Š” Typescript์™€ ํ•จ๊ป˜ Vue๋ฅผ ์„ค์น˜ํ• ๋•Œ Vue CLI์—์„œ ๋‚ด์žฅ๋œ Typescript ์˜ต์…˜์„ ์„ ํƒํ•ด ์„ค์น˜ํ•  ์ˆ˜ ์žˆ๋‹ค. Typescipt๋ฅผ ์„ ํƒํ•˜๋ฉด ์šฐ๋ฆฌ๋Š” tsconfig.json ํŒŒ์ผ(๋ณดํ†ต ๋ธŒ๋ผ์šฐ์ €์˜ ์ตœ๋Œ€ ์ง€์›์„ ์œ„ํ•ด ECMAScript 2009 ์„ค์ •)์—์„œ Javascript๋กœ ํŠธ๋žœ์ŠคํŒŒ์ผํ•˜๊ธฐ ์œ„ํ•œ ๊ตฌ์„ฑ์„ ํ•  ์ˆ˜ ์žˆ๋‹ค.

 

    // tsconfig.json
    {
      "compilerOptions": {
        // Vue์˜ ๋ธŒ๋ผ์šฐ์ € ์ง€์›์„ ์œ„ํ•ด
        "target": "es5",
        // ์ด๋ฅผ ํ†ตํ•ด 'this'์— ๋Œ€ํ•œ ๋ฐ์ดํ„ฐ ์†์„ฑ์„ ์—„๊ฒฉํ•˜๊ฒŒ ์ถ”๋ก ํ•  ์ˆ˜ ์žˆ์Œ
        "strict": true,
        // webpack 2+ ๋˜๋Š” rollup์„ ์‚ฌ์šฉํ•˜๋Š” ๊ฒฝ์šฐ ํŠธ๋ฆฌ ์‰์ดํ‚น์„ ํ™œ์šฉํ•˜๋ ค๋ฉด ์•„๋ž˜๋ฅผ ์ž…๋ ฅ
        "module": "es2015",
        "moduleResolution": "node"
      }
    }

 

๊ทธ๋ฆฌ๊ณ  ๋‚˜์„œ ์ปดํฌ๋„ŒํŠธ ์ƒ์„ฑ์‹œ Vue๋ฅผ ์ฐธ์กฐํ•˜๋ฉด Typescript ํƒ€์ž… ์ถ”๋ก ์„ ์–ป๊ฒŒ ๋œ๋‹ค.

 

    
    import Vue from 'vue'

    const Component = Vue.extend({
      // ...
    })

 

๋˜ํ•œ Vue๋ฅผ ์‚ฌ์šฉํ•˜๋ฉด ๋‹ค์Œ๊ณผ ๊ฐ™์ด ํด๋ž˜์Šค๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ๊ณ ์œ ํ•œ ํŠน๋ณ„ํ•œ ๋ฐฉ์‹์œผ๋กœ Typescript๋ฅผ ์‚ฌ์šฉํ•ด ์ปดํฌ๋„ŒํŠธ๋ฅผ ์ž‘์„ฑํ•  ์ˆ˜ ์žˆ๋‹ค.

 

    
    <template>
      <button @click="onClick">Click!</button>
    </template>


    <script lang="ts">
        import * as Vue from "vue";
        import { Component } from "vue-property-decorator";

        @Component()
        class App extends Vue {
          public message: string = "Hello World";

          public onClick(): void {
            window.alert(this.message);
          }
        }

        export default App;
    </script>

 

์—ฌ๊ธฐ์„œ ์ผ๋ถ€ Typescript ์–ด๋…ธํ…Œ์ด์…˜๊ณผ ํ•จ๊ป˜ Javascript ์นœํ™”์ ์ธ ๊ตฌ๋ฌธ์„ ๋ณผ ์ˆ˜ ์žˆ๋‹ค. ์˜ˆ๋ฅผ ๋“ค์–ด Angular๋Š” Typescript์™€ ํ•จ๊ป˜ ์„ค์น˜๋˜๊ณ  Typescript๋ฅผ ๊ฑฐ์˜ ๋…์ ์ ์œผ๋กœ ์‚ฌ์šฉํ•œ๋‹ค. ํ•œ๋•Œ Angular ์•ฑ์„ ์ˆœ์ˆ˜ Javascript๋กœ ์ž‘์„ฑํ•˜๋Š” ์˜ต์…˜์ด ์žˆ์—ˆ๋Š”๋ฐ ์ธ๊ธฐ๋ฅผ ๋Œ์ง€๋Š” ๋ชปํ–ˆ๋‹ค.

 

โš™๏ธ ํ”„๋กœ์ ํŠธ์— Flow ์„ค์น˜ํ•˜๊ธฐ

๋ฐ˜๋ฉด์—, Babel ๊ตฌ์„ฑ์— Flow ์ง€์›์„ ํ™œ์„ฑํ™”ํ•ด ํ”„๋กœ์ ํŠธ์— Flow๋ฅผ ์ถ”๊ฐ€ํ•  ์ˆ˜๋„ ์žˆ๋‹ค.

 

Flow๋ฅผ ์ถ”๊ฐ€ํ•˜๊ธฐ ์œ„ํ•ด ์•„๋ž˜ ๋ช…๋ น์–ด๋ฅผ ์‹คํ–‰ํ•œ๋‹ค.

 

npm install --save-dev @babel/preset-flow

 

๊ทธ๋ฆฌ๊ณ  .babelrc์— ๋‹ค์Œ ์ฝ”๋“œ๋ฅผ ์ถ”๊ฐ€ํ•œ๋‹ค.


    {
      "presets": ["@babel/preset-flow"]
    }

 

โš™๏ธ ํ”„๋กœ์ ํŠธ์— PropTypes ์„ค์น˜ํ•˜๊ธฐ

ํ”„๋กœ์ ํŠธ์— PropTypes๋ฅผ ์ถ”๊ฐ€ํ•˜๊ธฐ ์œ„ํ•ด PropTypes ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ๋ฅผ ์ถ”๊ฐ€ํ•˜๊ณ , ์ปดํฌ๋„ŒํŠธ์˜ prop types๋ฅผ ์ •์˜ํ•˜๊ณ  PropTypes.checkPropTypes์„ ํ˜ธ์ถœํ•œ๋‹ค.

 

Prop Types๋ฅผ ์„ค์น˜ํ•˜๊ธฐ ์œ„ํ•ด ๋‹ค์Œ ๋ช…๋ น์–ด๋ฅผ ํ˜ธ์ถœํ•œ๋‹ค.

 

npm install --save prop-types

 

๊ทธ๋ฆฌ๊ณ  ๋‚˜์„œ ์ปดํฌ๋„ŒํŠธ์˜ prop type ์œ ํšจ์„ฑ ๊ฒ€์ฆ์„ ์ •์˜ํ•˜๊ณ  ํ”„๋กœํผํ‹ฐ์™€ values ๊ฐ์ฒด๋ฅผ ์„ค์ •ํ•œ๋‹ค.

 

    
    const myPropTypes = {
      name: PropTypes.string,
      age: PropTypes.number,
      // ... prop types ๊ฒ€์ฆ์„ ์ •์˜ํ•œ๋‹ค
    };

    const props = {
      name: 'hello', // ์œ ํšจ
      age: 'world', // ์œ ํšจํ•˜์ง€ ์•Š์Œ
    };

 

๊ทธ๋ฆฌ๊ณ  Prop Type์„ ์ฒดํฌํ•œ๋‹ค.

 

   
   	// 'MyComponent' ์ปดํฌ๋„ŒํŠธ๋กœ ์ •์˜ํ•œ๋‹ค

    // Works with standalone PropTypes
    PropTypes.checkPropTypes(myPropTypes, props, 'age', 'MyComponent');

    // ๋‹ค์Œ๊ณผ ๊ฐ™์€ ์—๋Ÿฌ๋ฅผ ๋ฐ˜ํ™˜ํ•œ๋‹ค
    // Warning: Failed prop type: Invalid prop `age` of type `string` supplied to
    // `MyComponent`, expected `number`.

 

ํƒ€์ž… ์ •์˜์™€ ๊ตฌ๋ฌธ ์ฒดํฌ

 

์•ž์„œ ์–ธ๊ธ‰ํ•œ ๊ฒƒ์ฒ˜๋Ÿผ ์„ธ ๊ฐ€์ง€ ๊ธฐ์ˆ  ๋ชจ๋‘ ๋ณ€์ˆ˜์— ๋Œ€ํ•œ ํƒ€์ž… ์ฒดํฌ ๋ฐ ์ œํ•œ์„ ์ œ๊ณตํ•˜๋ฉฐ ์ด๊ฒƒ๋“ค์„ ๋น„๊ตํ•ด ๋ณด๋ ค ํ•œ๋‹ค.

 

๐Ÿ› ๏ธ Flow์™€ Typescript์˜ ํƒ€์ž… ์ •์˜

Flow์™€ Typescript๋Š” ์ƒ๋‹นํžˆ ์œ ์‚ฌํ•œ ํƒ€์ž… ์ •์˜ ๊ตฌ๋ฌธ์„ ๊ฐ–๊ณ  ์žˆ๋‹ค.

 

๊ณตํ†ต์ :

  • ๋ณ€์ˆ˜ ํƒ€์ž… ์ฒดํฌ์— ๋Œ€ํ•œ Javascript ์›์‹œ ํƒ€์ž…๊ณผ ํŒŒ์ƒ(๊ฐ์ฒด)๋œ ํƒ€์ž…์„ ์ œ๊ณต
  • ์œ ์‚ฌํ•œ ํƒ€์ž… ์–ด๋…ธํ…Œ์ด์…˜ ๊ตฌ๋ฌธ์„ ๊ฐ€์ง€๊ณ  ์žˆ์Œ
  •  ์—ฐ์‚ฐ์ž์™€ ๋‹ค์–‘ํ•œ ์œ ํ‹ธ๋ฆฌํ‹ฐ ํƒ€์ž…์„ ์‚ฌ์šฉํ•˜์—ฌ Javascript ํƒ€์ž… ์‹œ์Šคํ…œ์˜ ์œ ์—ฐ์„ฑ์„ ์œ ์ง€
  • ์„ ํƒ์  ํ”„๋กœํผํ‹ฐ์— ๋Œ€ํ•œ ํƒ€์ž…, ์ฆ‰ Typescript๋Š” nullable ํƒ€์ž…์ด ์žˆ๊ณ  Flow์—๋Š” maybe ํƒ€์ž…์ด ์žˆ์Œ
  • ๋ณ€์ˆ˜ ํƒ€์ž…์„ ๊ฐ–๋Š” ์ฝ”๋“œ๋ฅผ ์ž‘์„ฑํ•˜๋Š”๋ฐ ์‚ฌ์šฉํ•˜๋Š” ์ œ๋„ˆ๋ฆญ์ด ์žˆ์Œ

 

๋งˆ์ง€๋ง‰ ๊ณตํ†ต์ ์˜ ์˜ˆ์‹œ๋Š” ์•„๋ž˜์— ์žˆ๋‹ค.

function identity<T>(value: T): T {
    return value
}

 

์ œ๋„ค๋ฆญ์€ ๋‹ค๋ฅธ ํƒ€์ž…๋“ค๋กœ ๋ฎ์–ด ์”Œ์—ฌ์งˆ ์ˆ˜ ์žˆ๋Š” ๋ณ€์ˆ˜ ํƒ€์ž…์„ ๊ฐ€์ง„๋‹ค :

identity<string>('foo').

 

๋˜ํ•œ ๋‹ค์Œ ์ฝ”๋“œ๋Š” Typescript์™€ Flow์—์„œ ๋™์ผํ•˜๋‹ค. ์—ฌ๊ธฐ์„œ ํ•จ์ˆ˜ concat์€ ๋ฌธ์ž ์œ ํ˜•์ธ ๋‘ ๋ณ€์ˆ˜๋ฅผ ๊ฐ€์ง€๊ณ  ๋‘˜์˜ ํ•ฉ์„ ๋ฐ˜ํ™˜ํ•œ๋‹ค.

 


    function concat(a: string, b: string) {
      return a + b;
    }

 

๐Ÿ› ๏ธ PropTypes์˜ ํƒ€์ž… ์œ ํšจ์„ฑ ๊ฒ€์‚ฌ๊ธฐ

๋ฐ˜๋ฉด์— PropTypes๋Š” ์ปดํฌ๋„ŒํŠธ์˜ ํ”„๋กœํผํ‹ฐ ์„ค์ •์„ ์œ„ํ•ด ์ž์ฒด ํƒ€์ž… ์œ ํšจ์„ฑ ๊ฒ€์‚ฌ๊ธฐ๋ฅผ ์‚ฌ์šฉํ•œ๋‹ค. ์ฆ‰, PropTypes์—์„œ๋Š” PropTypes ๊ฐ์ฒด๋ฅผ ์‚ฌ์šฉํ•ด ํƒ€์ž…์„ ์ •์˜ํ•œ๋‹ค.

 

    
    import React from 'react';
    import PropTypes from 'prop-types'

    class MyComponent extends React.Component {
      render() {
        // ... do things with the props
      }
    }

    MyComponent.propTypes = {
      optionalArray: PropTypes.array,
    ...

 

๐Ÿ› ๏ธ ํƒ€์ž… ์บ์ŠคํŒ…

Flow์™€ Typescript ๋ชจ๋‘ ๋ณ€์ˆ˜๋ฅผ ํ•œ ํƒ€์ž…์—์„œ ๋‹ค๋ฅธ ํƒ€์ž…์œผ๋กœ ๋ช…์‹œ์ ์œผ๋กœ ์บ์ŠคํŒ…ํ•˜๋Š” ๊ธฐ๋Šฅ์„ ์ œ๊ณตํ•œ๋‹ค.

 

Flow์—์„œ๋Š” ๊ธฐํ˜ธ : ๋ฅผ ์‚ฌ์šฉํ•ด ์บ์ŠคํŒ…ํ•˜๊ณ  Typescript์—์„œ๋Š” as ํ‚ค์›Œ๋“œ๋ฅผ ์‚ฌ์šฉํ•ด ์บ์ŠคํŒ…ํ•œ๋‹ค.

 

    
    // TypeScript
    let value = 1 as number;

    // Flow
    let value = 1;
    (value: number);

 

PropTypes๋Š” ํ•œ ํƒ€์ž…์—์„œ ๋‹ค๋ฅธ ํƒ€์ž…์œผ๋กœ ๋ช…์‹œ์ ์œผ๋กœ ์บ์ŠคํŒ…ํ•˜๋Š” ๊ธฐ๋Šฅ์„ ์ œ๊ณตํ•˜์ง€ ์•Š๋Š”๋‹ค.

 

๐Ÿ› ๏ธ Interfaces, enums, ์ปค์Šคํ…€ ํƒ€์ž…

Interface๋Š” ๊ฐ์ฒด์˜ ๊ตฌ์กฐ์™€ ํ”„๋กœํผํ‹ฐ๋ฅผ ์ œํ•œํ•˜๋Š” ํƒ€์ž… ์ •์˜์ด๋‹ค. Enums๋Š” ์—ด๊ฑฐ๋œ ๊ฐ’๋“ค์ด๋ฉฐ ๋ณ€์ˆ˜๋ฅผ enum ๊ฐ’ ์ค‘ ํ•˜๋‚˜๋กœ ์ œํ•œํ•ด ํƒ€์ž…์œผ๋กœ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๋‹ค. Flow, TypeScript ๋ฐ PropTypes๋ฅผ ์‚ฌ์šฉํ•˜๋ฉด ์ปค์Šคํ…€ ํƒ€์ž… ์ œํ•œ์„ ํ•  ์ˆ˜ ์žˆ๋‹ค.

 

Flow์™€ TypeScript๋Š” interface ํ‚ค์›Œ๋“œ๋ฅผ ์‚ฌ์šฉํ•ด ์ปค์Šคํ…€ ํƒ€์ž… ๊ฐ์ฒด๋ฅผ ์ •์˜ํ•œ๋‹ค. ๋ชจ๋‘ implements ํ‚ค์›Œ๋“œ๋ฅผ ์‚ฌ์šฉํ•ด ํด๋ž˜์Šค๊ฐ€ ์ธํ„ฐํŽ˜์ด์Šค์˜ ๊ตฌ์กฐ๋ฅผ ์ƒ์†ํ•  ์ˆ˜ ์žˆ๊ฒŒ ํ•œ๋‹ค.  ์•„๋ž˜ ์˜ˆ์‹œ๋ฅผ ์‚ดํŽด๋ณด์ž.

 

    
    interface PersonInterface {
      firstName: string;
      lastName: string;
      fullName(firstName: string, lastName: string): string
    }

    class Person implements PersonInterface {
        firstName: string;
        lastName: string;
        constructor(firstName: string, lastName: string){
            this.firstName = firstName;
            this.lastName = lastName;
        }

        fullName(firstName: string, lastName: string): string {
            return `${firstName} ${lastName}`;
        }
    }

 

๋งŒ์•ฝ ์ธํ„ฐํŽ˜์ด์Šค์— ์žˆ๋Š” ๋ชจ๋“  ๊ฐ’์„ ๊ตฌํ˜„ํ•˜์ง€ ์•Š์œผ๋ฉด Flow์™€ Typescript๋Š” ์—๋Ÿฌ๋ฅผ ๋ฐ˜ํ™˜ํ•  ๊ฒƒ์ด๋‹ค.

 

Flow์™€ Typescript ๋˜ํ•œ ํƒ€์ž… ์ฒดํ‚น์„ ์œ„ํ•ด enum ํ‚ค์›Œ๋“œ๋ฅผ ์‚ฌ์šฉํ•ด  enum ๋ฆฌ์ŠคํŠธ๋ฅผ ์ •์˜ํ•œ๋‹ค.

 

enum Status {
  Active,
  Paused,
  Off,
}

const status: Status = Status.Active //์ผ์น˜
const wrongStatus: Status = 'test' //๋ถˆ์ผ์น˜, ์ •์˜๋œ ํƒ€์ž…์„ ๋”ฐ๋ฅด์ง€ ์•Š์Œ

 

ํ•œ ๊ฐ€์ง€ ๋…ํŠนํ•œ Flow์˜ ํŠน์ง•์€ ํƒ€์ž… ์ฒดํ‚น ์ฝ”๋“œ๋ฅผ ์•„๋ž˜์™€ ๊ฐ™์ด ์ฃผ์„์— ์“ด๋‹ค๋Š” ์ ์ด๋‹ค.

function greet(greeting /*: string*/) /* : string */ {
  return greeting;
}

 

ํƒ€์ž…์Šคํฌ๋ฆฝํŠธ์—์„œ๋Š” ์ด๋ฅผ ์‚ฌ์šฉํ•  ์ˆ˜ ์—†๋‹ค. ๊ทธ๋Ÿฌ๋‚˜ ์ฃผ์„์—๋Š” ์ž๋™์™„์„ฑ ๋˜๋Š” ๊ตฌ๋ฌธ ํ•˜์ด๋ผ์ดํŠธ ๊ธฐ๋Šฅ์ด ์—†๊ธฐ ๋•Œ๋ฌธ์— ์ด๋Š” ํฐ ์žฅ์ ์ด ์•„๋‹ˆ๋‹ค.

 

๋ฐ˜๋ฉด์— PropTypes์€ ์•„๋ž˜์™€ ๊ฐ™์ด PropTypes.oneof๋ฅผ ์‚ฌ์šฉํ•ด enum ํƒ€์ดํ•‘์„ ์ •์˜ํ•œ๋‹ค. 

 

...
optionalEnum: PropTypes.oneOf(['News', 'Photos']),
...

 

PropTypes๋Š” ๋˜ํ•œ PropTypes.shape์„ ์ด์šฉํ•ด ๊ฐ์ฒด ํƒ€์ž… ๊ตฌ์กฐ๋ฅผ ์ •์˜ํ•œ๋‹ค.

 

...
optionalObjectWithShape: PropTypes.shape({
    optionalProperty: PropTypes.string,
    requiredProperty: PropTypes.number.isRequired
}),
...

 

๐Ÿ”ง ํ…์ŠคํŠธ ์—๋””ํ„ฐ ์ง€์›

 

Flow์™€ Typescript ๋ชจ๋‘ Visual Studio Code์™€ Sublime๊ณผ ๊ฐ™์€ ์—๋””ํ„ฐ๊ฐ€ ์ง€์›ํ•˜๋Š” ๋‚ด์žฅ๋œ ํ”Œ๋Ÿฌ๊ทธ์ธ ์ง€์›์„ ๊ฐ€์ง€๊ณ  ์žˆ๋‹ค.

 

Flow์™€ TypeScript์— ๋Œ€ํ•œ ์—๋””ํ„ฐ ์ง€์›์€ ๊ฐœ๋ฐœ์ž๊ฐ€ ๋‹ค์Œ๊ณผ ๊ฐ™์€ ๊ธฐ๋Šฅ์„ ์‚ฌ์šฉํ•˜๋Š” ๊ฒƒ์„ ์˜๋ฏธํ•œ๋‹ค.

 

  • IntelliSense (์ž๋™์™„์„ฑ)
  • Go to Definition(์ •์˜๋กœ ์ด๋™) / Peek Definition (์ •์˜ ๋ณด๊ธฐ)
  • Diagnostics(์ง„๋‹จ) (Errors, Warnings)
  • ํƒ€์ž… ์ •๋ณด hover
  • ์ „ํ™˜ ๊ฐ€๋Šฅํ•œ ์ฝ”๋“œ ์ ์šฉ ๋ฒ”์œ„ ๋ฆฌํฌํŠธ

Babel์„ ํ†ตํ•ด ๊ธฐ์กด ํ”„๋กœ์ ํŠธ์— Flow ์„ค์น˜๋ฅผ ์ง€์›ํ•˜๋Š” ๋ฌธ์„œ๋„ ์žˆ์Šต๋‹ˆ๋‹ค. Flow ์ง€์› ๋ฐ TypeScript ์—๋””ํ„ฐ ์ง€์›์„ ์œ„ํ•œ ์—๋””ํ„ฐ/IDE ์„ค์น˜์— ๋Œ€ํ•œ ์ž์„ธํ•œ ๋‚ด์šฉ์„ ์ฝ์–ด๋ณด์„ธ์š”.

 

PropTypes ๋˜ํ•œ ํ• ๋‹น๋œ ๊ฐ’์— ๋Œ€ํ•ด ์ปดํฌ๋„ŒํŠธ์˜ prop types์„ ์ž๋™ ์ƒ์„ฑํ•ด์ฃผ๋Š” Visual Studiio code ๊ธฐ๋Šฅ์ด ์žˆ๋‹ค.

 

PropTypes์—๋Š” PropTypes.checkPropTypes๋ฅผ ํ˜ธ์ถœํ•˜์—ฌ ๋‹ค๋ฅธ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ์— ์ ์šฉํ•  ์ˆ˜๋„ ์žˆ๋‹ค(React์—์„œ๋Š” ์ž๋™์œผ๋กœ ํ˜ธ์ถœ๋จ). PropTypes์˜ ๊ณต์‹ ๋ฌธ์„œ์—๋Š” ๋‹ค๋ฅธ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ ์ง€์›์— ๋Œ€ํ•œ ์–ธ๊ธ‰์ด ์žˆ์ง€๋งŒ, ์ด๊ฒƒ์ด ๋‹ค๋ฅธ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ์—์„œ ์–ด๋–ป๊ฒŒ ์ž‘๋™ํ•˜๋Š”์ง€์— ๋Œ€ํ•œ ์™ธ๋ถ€ ๋ฌธ์„œ๋Š” ๋งŽ์ง€ ์•Š๋‹ค.

 

๐Ÿ”ง ํšจ์œจ์„ฑ๊ณผ ์„ฑ๋Šฅ

Flow๊ณผ Typescript์˜ ์„ฑ๋Šฅ์˜ ์ฐจ์ด๋Š” ์ž‘๋‹ค. TypeScript๋Š” ์ง€์†์ ์œผ๋กœ 500-600MB์˜ RAM์„ ์‚ฌ์šฉํ•˜๋ฉฐ Flow๋„ ํฌ๊ฒŒ ๋‹ค๋ฅด์ง€ ์•Š๋‹ค. ์ปดํ“จํŒ… ์ž์›์˜ ํšจ์œจ์„ฑ ์ธก๋ฉด์—์„œ๋Š” ๋‘˜ ์‚ฌ์ด์— ํฐ ์ฐจ์ด๊ฐ€ ์—†๋‹ค.

 

PropTypes์˜ ํšจ์œจ์„ฑ? ์ด Reddit ์Šค๋ ˆ๋“œ์— ๋”ฐ๋ฅด๋ฉด TypeScript๋Š” ๋” ๋น ๋ฅด๊ณ  ๋ฒ„๊ทธ๊ฐ€ ์ ๋‹ค. 

 

๐Ÿ‘ฅ  ์ปค๋ฎค๋‹ˆํ‹ฐ ์ง€์›

TypeScript์˜ ์ปค๋ฎค๋‹ˆํ‹ฐ๋Š” Flow ๋ฐ PropTypes๊ณผ ๋น„๊ตํ•˜๋ฉด ๊ฐ€์žฅ ํฌ๋‹ค. Flow์™€ PropTypes๋Š” ์ด์ „์— ๋งํ–ˆ๋˜ ๊ฒƒ์ฒ˜๋Ÿผ ๊ณต์‹ ์†Œ์Šค๋ฅผ ์ œ์™ธํ•˜๋ฉด ๋ฌธ์„œ๊ฐ€ ์ ๊ณ  StackOverflow์˜ ์งˆ๋ฌธ๋„ ์ ๋‹ค. 

 

Vue, Angular ๋ฐ React ๊ฐ™์€ ๋งŽ์€ ํ”„๋ก ํŠธ์—”๋“œ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ, ํ”„๋ ˆ์ž„์›Œํฌ ๋ฐ ํ”Œ๋žซํผ์—๋Š” TypeScript์— ๋Œ€ํ•œ ์ง€์›์ด ๋‚ด์žฅ๋˜์–ด ์žˆ๋‹ค. Express์™€ ๊ฐ™์€ Node.js ์›น ํ”„๋ ˆ์ž„์›Œํฌ์— TypeScript๋ฅผ ์ถ”๊ฐ€ํ•  ์ˆ˜ ์žˆ์œผ๋ฉฐ Nest.js๋Š” TypeScript๊ฐ€ ๋‚ด์žฅ๋˜์–ด ์žˆ๋Š” ์ƒํƒœ๋กœ ๊ตฌ์ถ•๋˜์–ด ํ”„๋กœ์ ํŠธ๋ฅผ ํฌ๊ฒŒ ๋ณ€๊ฒฝํ•˜์ง€ ์•Š๊ณ  TypeScript๋ฅผ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๋‹ค.

 

Express์—์„œ TypeScript๋ฅผ ์‚ฌ์šฉํ•˜๋ ค๋ฉด ๋‹ค์Œ ๋ช…๋ น์„ ์‹คํ–‰ํ•˜์—ฌ TypeScript ํŠธ๋žœ์ŠคํŒŒ์ผ๋Ÿฌ๋ฅผ ์„ค์น˜ํ•˜๋ฉด ๋œ๋‹ค.

 

npm install --save-dev typescript

 

๊ทธ๋Ÿฐ ๋‹ค์Œ tsconfig.json ํŒŒ์ผ์„ ์ถ”๊ฐ€ํ•ด ๋‹ค์Œ๊ณผ ๊ฐ™์ด ์ž‘์„ฑํ•˜์—ฌ TypeScript ํŠธ๋žœ์ŠคํŒŒ์ผ๋Ÿฌ๋ฅผ ๊ตฌ์„ฑํ•  ์ˆ˜ ์žˆ๋‹ค.

 

{
    "compilerOptions": {
        "module": "commonjs",
        "esModuleInterop": true,
        "target": "es6",
        "noImplicitAny": true,
        "moduleResolution": "node",
        "sourceMap": true,
        "outDir": "dist",
        "baseUrl": ".",
        "paths": {
            "*": [
                "node_modules/*"
            ]
        }
    },
    "include": [
        "src/**/*"
    ]
}

 

 

Express ๋ฐ Node์— ๋Œ€ํ•œ ํƒ€์ž… ์ •์˜๋ฅผ ์„ค์น˜ํ•˜๋ ค๋ฉด ๋‹ค์Œ์„ ์‹คํ–‰ํ•œ๋‹ค.

npm install --save-dev @types/node @types/express

 

๋ณด๋‹ค์‹œํ”ผ, ๋งŽ์€ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ์™€ ํ”„๋ ˆ์ž„์›Œํฌ์— ๋Œ€ํ•ด TypeScript ํƒ€์ž… ์ •์˜๊ฐ€ ์กด์žฌํ•˜๊ธฐ ๋•Œ๋ฌธ์— ๊ธฐ์กด ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ์—์„œ TypeScript๋ฅผ ์‚ฌ์šฉํ•˜๋Š” ๊ฒƒ์ด ๊ทธ๋ฆฌ ์–ด๋ ต์ง€ ์•Š๋‹ค. TypeScript์— ๋Œ€ํ•œ ๋” ๋งŽ์€ ํƒ€์ž… ์ •์˜๋ฅผ ๋ณด๋ ค๋ฉด ํ™•์‹คํžˆ ํƒ€์ž…์ด ์ง€์ •๋œ ์›น ์‚ฌ์ดํŠธ๋กœ ์ด๋™ํ•ด ๋ณด๋ฉด ๋œ๋‹ค.

 

๐Ÿ“„ ๋ฆฌ์†Œ์Šค์™€ ๋ฌธ์„œ

 

TypeScript๋Š” ์‚ฌ์šฉ ๊ฐ€๋Šฅํ•œ ๋ฆฌ์†Œ์Šค ๋ฐ ๋ฌธ์„œ์˜ ์–‘ ์ธก๋ฉด์—์„œ ํ™•์‹คํžˆ ๋‹ค๋ฅธ ์ •์  ํƒ€์ž… ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ๋ณด๋‹ค ๊ฒฝ์Ÿ๋ ฅ์ด ์žˆ๋‹ค.
TypeScript๋Š” ๋‹ค์Œ์„ ์ œ๊ณตํ•œ๋‹ค:

 

์ถ”๊ฐ€ ์ด์ ์œผ๋กœ TypeScript์˜ ํ”Œ๋ ˆ์ด๊ทธ๋ผ์šด๋“œ๋Š” ๋‹ค์–‘ํ•œ ๋ฒ„์ „์˜ TypeScript๋ฅผ ์ง€์›ํ•˜๋ฏ€๋กœ ๋‹ค์–‘ํ•œ ๋ฒ„์ „์˜ TypeScript ํŠธ๋žœ์ŠคํŒŒ์ผ๋Ÿฌ์—์„œ ์ฝ”๋“œ๊ฐ€ ์–ด๋–ป๊ฒŒ ์ž‘๋™ํ•˜๋Š”์ง€ ํ™•์ธํ•  ์ˆ˜ ์žˆ๋‹ค.

 

๐Ÿ”ฎ ๊ฒฐ๋ก 

TypeScript๋Š” ๋งŽ์€ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ์™€ ํ”„๋ ˆ์ž„์›Œํฌ์—์„œ ์ง€์›๋˜๋ฏ€๋กœ ๋งŽ์€ ์‚ฌ๋žŒ๋“ค์ด ๋งค์ผ TypeScript๋ฅผ ์‚ฌ์šฉํ•˜๊ณ  ์žˆ๋‹ค. ๋งŽ์€ ์˜ˆ์ œ์™€ ์„ค๋ช…์„ ํฌํ•จํ•ด TypeScript์˜ ๊ฐ ๊ธฐ๋Šฅ์— ๋Œ€ํ•œ ๋งŽ์€ ์ •๋ณด๊ฐ€ ์žˆ๊ณ , ์ •์  ํƒ€์ดํ•‘์„ ๊ตฌํ˜„ํ•˜๋Š” ๋ฐ ๊ฐ€์žฅ ์ ํ•ฉํ•œ ์˜ต์…˜์ผ ๊ฐ€๋Šฅ์„ฑ์ด ๋†’๋‹ค.

 

๋ฐ˜๋ฉด Flow๋Š” React๋กœ Flow๋ฅผ ์„ค์ •ํ•˜๋Š” ๋ฐฉ๋ฒ•์— ๋Œ€ํ•œ ์ผ๋ถ€ ๋ฌธ์„œ์™€ ์งง์€ ๋ฌธ์„œ๋งŒ ์žˆ์œผ๋ฉฐ, ์ด๋Š” ๋‹ค๋ฅธ JavaScript ํ”„๋ ˆ์ž„์›Œํฌ์—์„œ Flow๋ฅผ ์„ค์ •ํ•˜๋Š” ๋ฐ์—๋„ ์ ์šฉํ•  ์ˆ˜ ์žˆ๋‹ค. ๋˜ํ•œ ์ง€๊ธˆ๊นŒ์ง€ PropTypes์€ ์„ธ ๊ฐ€์ง€ ์˜ต์…˜ ์ค‘ ๊ฐ€์žฅ ๋“œ๋ฌธ ๋ฌธ์„œ๋ฅผ ๊ฐ–๊ณ  ์žˆ์ง€๋งŒ ์ด๋Ÿฐ ๊ฒŒ์‹œ๋ฌผ๋„ ๋ช‡ ๊ฐœ ์žˆ๋‹ค.

 

 

 

๐ŸŽง ๋งˆ๋ฌด๋ฆฌ ๋…ธ๋ž˜ ์ถ”์ฒœ..

 

 

์š•์‹ฌ์˜ ๋ฐ˜๋Œ€ํŽธ์œผ๋กœ - ์ตœ์œ ๋ฆฌ

์Œ์•…์ด ํ•„์š”ํ•œ ์ˆœ๊ฐ„, ๋ฉœ๋ก 

www.melon.com

 

 

 

 

 

 

 

๐Ÿ„‍โ™€๏ธ input ํƒœ๊ทธ๋กœ ํŒŒ์ผ์„ ์—…๋กœ๋“œํ•˜๊ฑฐ๋‚˜ ํŒŒ์ผ์˜ url์„ ๊ฐ€์ง€๊ณ  ์žˆ์„ ๊ฒฝ์šฐ ํŒŒ์ผ์˜ ํ™•์žฅ์ž๋ฅผ ์ œ๋Œ€๋กœ ์•Œ ์ˆ˜ ์žˆ๋Š” ๋ฐฉ๋ฒ•์— ๋Œ€ํ•ด ์•Œ์•„๋ณด์ž.

 

 

How to: ํŒŒ์ผ ์—…๋กœ๋“œ ํ›„ e.target.files์˜ name์„ ํ™œ์šฉ

<input type="file" id="avatar" name="avatar" accept="*" />

 

 

 

 

์œ„ ํŒŒ์ผ ๊ฐ์ฒด๋Š” inputํƒœ๊ทธ๋ฅผ ํ†ตํ•ด ํŒŒ์ผ์„ ์—…๋กœ๋“œ ํ•œ ํ›„ ์–ป๊ฒŒ ๋˜๋Š” ๊ฐ’์ด๋‹ค.

 

๊ทธ ์ค‘ name๊ฐ’์—๋Š” ํŒŒ์ผ์˜ ์ด๋ฆ„์ด ์กด์žฌํ•˜๋Š”๋ฐ ์ด๋ฅผ ํ™œ์šฉํ•ด ํ™•์žฅ์ž ๊ฐ’์„ ๊ตฌํ•  ์ˆ˜ ์žˆ๋‹ค.

 

<input
    type="file"
    id="upload"
    onChange={(e) => {
      const files = e.target.files;
      const filename = files[0].name;
      const splitedNameArr = filename.split('.');
      const lastSplitedVal = splitedNameArr.at(-1);

      console.log(lastSplitedVal);
    }}
  />

 

ํŒŒ์ผ name์—์„œ split์„ ํ†ตํ•ด . ์„ ๊ธฐ์ค€์œผ๋กœ ๋‚˜๋ˆˆ ๋’ค ๋งˆ์ง€๋ง‰ . ๋’ค์˜ ๊ฐ’์„ ํ™•์žฅ์ž๋กœ ์ธ์‹ํ•˜๋Š” ๋ฐฉ๋ฒ•์„ ํ™œ์šฉํ–ˆ๋‹ค.

 

์ด๋ ‡๊ฒŒ ํ•˜๋ฉด ํŒŒ์ผ ์ด๋ฆ„ ์‚ฌ์ด์— . ์ด ์กด์žฌํ•˜๋”๋ผ๋„ ๊ฐ€์žฅ ๋งˆ์ง€๋ง‰ . ๋’ค ๊ฐ’์„ ํ™•์žฅ์ž๋กœ ๋ณผ ์ˆ˜ ์žˆ๋‹ค.

 

 

* Array.prototype.at() ๊ธฐ๋Šฅ์ด ๋„ˆ๋ฌด ๋ง˜์— ๋“ค์–ด ๋งํฌ ๋‚จ๊ธด๋‹ค!

https://developer.mozilla.org/ko/docs/Web/JavaScript/Reference/Global_Objects/Array/at

์ถœ์ฒ˜: https://www.udemy.com/course/learn-flutter-dart-to-build-ios-android-apps/

 

 

 

 

 

 

๐Ÿ“ lib - main.dart๋ฅผ ๊ฐ€์ง€๊ณ  ์žˆ๋Š” ํด๋”, ๊ฐ€์žฅ ์ค‘์š”ํ•œ ํด๋”. ๊ฐ€์žฅ ๋งŽ์€ ์‹œ๊ฐ„์„ ๋ณด๋‚ผ ํด๋”

 

๐Ÿ“„ lib/main.dart - flutter ์•ฑ์˜ entry point ์—ญํ• 

 

๐Ÿ–‡import ...; - DartํŒŒ์ผ์„ importํ•˜๊ธฐ ์œ„ํ•œ ๋ฐฉ๋ฒ•

 

 

Flutter UI๋Š” Widgets๊ณผ ํ•จ๊ป˜ ๋นŒ๋“œ๋œ๋‹ค. Combining(๊ฒฐํ•ฉ) & Nesting(์ค‘์ฒฉ) ์„ ํ†ตํ•ด.

 

 

๐Ÿ“ android,ios - flutter๊ฐ€ android,ios๋ฅผ ์‹คํ–‰ํ•˜๊ธฐ ์œ„ํ•œ ํŒŒ์ผ

 

๐Ÿ“ build - ๋นŒ๋“œ๋  ๋•Œ๋งˆ๋‹ค flutter๊ฐ€ ์•Œ์•„์„œ ๋ณ€๊ฒฝํ•ด์ฃผ๋Š” ๋นŒ๋“œ ํด๋”(๊ฑด๋“œ๋ฆด ์ผ์ด ์—†๋‹ค)

 

๐Ÿ“„ pubspec.yaml - ํ”„๋กœ์ ํŠธ์˜ dependencies์™€ ์ด์— ๋Œ€ํ•œ ๋ฉ”ํƒ€๋ฐ์ดํ„ฐ ์ •๋ณด, Flutter sdk ์ •๋ณด ๋“ฑ์„ ์ €์žฅํ•˜๋Š” ๊ณต๊ฐ„ (font, image, image ํŒŒ์ผ๋“ค..)

 

๐Ÿ“ test - ์‹คํ–‰ํ•˜๊ธฐ ์ „ testํŒŒ์ผ์„ ํ†ตํ•ด main.dart์˜ ์—๋Ÿฌ๋ฅผ ๋จผ์ € ๋ฐœ๊ฒฌํ•  ์ˆ˜ ์žˆ๊ฒŒ ํ•ด์ฃผ๋Š” ํด๋”

 

 

 

 

+ Recent posts