๐Ÿณ React์—์„œ์˜ ์ˆœ์ˆ˜ ์ปดํฌ๋„ŒํŠธ

@leedawn ยท March 04, 2024 ยท 8 min read

์ˆœ์ˆ˜ ํ•จ์ˆ˜๋ž€ ๋ฌด์—‡์ธ๊ฐ€?

์ˆœ์ˆ˜ ํ•จ์ˆ˜๋ž€ ์‚ฌ์ด๋“œ ์ดํŽ™ํŠธ๊ฐ€ ์—†๋Š” ํ•จ์ˆ˜, ์ฆ‰ ํ•จ์ˆ˜์˜ ์‹คํ–‰์ด ์™ธ๋ถ€์— ์˜ํ–ฅ์„ ๋ผ์น˜์ง€ ์•Š๋Š” ํ•จ์ˆ˜๋ฅผ ๋œปํ•˜๊ณ  ์ž…๋ ฅ์œผ๋กœ ์ „๋‹ฌ๋œ ๊ฐ’์„ ์ˆ˜์ •ํ•˜์ง€ ์•Š๋Š” ๋ถˆ๋ณ€์„ฑ์„ ๊ฐ€์ง€๊ณ  ์žˆ๋‹ค. ๋”ฐ๋ผ์„œ ์ˆœ์ˆ˜ํ•จ์ˆ˜๋Š” ์–ด๋– ํ•œ ์ „๋‹ฌ์ธ์ž๊ฐ€ ์ฃผ์–ด์ง€๋”๋ผ๋„ ํ•ญ์ƒ ๋˜‘๊ฐ™์€ ๊ฐ’์ด ๋ฆฌํ„ด๋จ์„ ๋ณด์žฅํ•œ๋‹ค.

  • ์‚ฌ์ด๋“œ ์ดํŽ™ํŠธ๋ฅผ ๋งŒ๋“ค์ง€ ์•Š๋Š”๋‹ค. ํ•จ์ˆ˜๋Š” ์ž…๋ ฅ๋ฐ›์€ ๊ฐ’๋งŒ์„ ๊ฐ€์ง€๊ณ  ๊ฒฐ๊ณผ๋ฅผ ๋ฐ˜ํ™˜ํ•˜๋ฉฐ, ๊ทธ ์™ธ ์–ด๋–ค ์™ธ๋ถ€ ์ƒํƒœ๋„ ๋ณ€๊ฒฝํ•˜์ง€ ์•Š๋Š”๋‹ค.
  • ๋™์ผ ์ž…๋ ฅ, ๋™์ผ ์ถœ๋ ฅ. ๋™์ผํ•œ ์ž…๋ ฅ์— ๋Œ€ํ•ด ์ˆœ์ˆ˜ ํ•จ์ˆ˜๋Š” ์–ธ์ œ๋‚˜ ๋™์ผํ•œ ๊ฒฐ๊ณผ๋ฅผ ์ถœ๋ ฅํ•œ๋‹ค.

์‚ฌ์ด๋“œ ์ดํŽ™ํŠธ๋ž€?

ํ•จ์ˆ˜์˜ ์ž…๋ ฅ ์™ธ์—๋„ ํ•จ์ˆ˜์˜ ๊ฒฐ๊ณผ์— ์˜ํ–ฅ์„ ๋ฏธ์น˜๋Š” ์š”์ธ์ด๋‹ค. ๋Œ€ํ‘œ์ ์œผ๋กœ ๋„คํŠธ์›Œํฌ ์š”์ฒญ,
API ํ˜ธ์ถœ์ด side effect์ด๋‹ค.

์ˆœ์ˆ˜ ํ•จ์ˆ˜ ๊ฐœ๋…์ด ์ค‘์š”ํ•œ ์ด์œ ๋Š”?

์‚ฌ์ด๋“œ ์ดํŽ™ํŠธ๋ฅผ ์ค„์ด๊ณ , ๋ชจ๋“ˆํ™” ์ˆ˜์ค€์„ ๋†’์ด๋Š” ํ•จ์ˆ˜ํ˜• ํ”„๋กœ๊ทธ๋ž˜๋ฐ์˜ ํŠน์ง•, ์ฆ‰ ์ˆœ์ˆ˜ ํ•จ์ˆ˜๋Š” ํ‰๊ฐ€ ์‹œ์ ์ด ๋ฌด๊ด€ํ•˜๋‹ค๋Š” ํŠน์ง•์œผ๋กœ ์ธํ•ด ํšจ์œจ์ ์ธ ๋กœ์ง์„ ๊ตฌ์„ฑํ•  ์ˆ˜ ์žˆ๋‹ค.

React์—์„œ์˜ ์ˆœ์ˆ˜ ์ปดํฌ๋„ŒํŠธ๋ž€?

React๋Š” ์ˆœ์ˆ˜ ํ•จ์ˆ˜๋ฅผ ์ค‘์‹ฌ์œผ๋กœ ์„ค๊ณ„๋˜์—ˆ๋‹ค. ๋ชจ๋“  ์ปดํฌ๋„ŒํŠธ๊ฐ€ ์ˆœ์ˆ˜ ํ•จ์ˆ˜๋ผ๊ณ  ๊ฐ€์ •ํ•œ๋‹ค.
์ฆ‰, ์šฐ๋ฆฌ๊ฐ€ ์ž‘์„ฑํ•˜๋Š” React ์ปดํฌ๋„ŒํŠธ๋Š” ๋™์ผํ•œ ์ž…๋ ฅ์ด ์ฃผ์–ด์กŒ์„ ๋•Œ ํ•ญ์ƒ ๋™์ผํ•œ JSX๋ฅผ ๋ฐ˜ํ™˜ํ•ด์•ผ ํ•œ๋‹ค.

๋‹ค์Œ ์ฝ”๋“œ๋Š” ๋ถˆ์ˆœํ•œ ์ปดํฌ๋„ŒํŠธ์˜ ์˜ˆ์‹œ์ด๋‹ค. ๐Ÿ˜’

let guest = 0

function Cup() {
  // Bad : ๊ธฐ์กด ๋ณ€์ˆ˜๋ฅผ ๋ณ€๊ฒฝํ•ฉ๋‹ˆ๋‹ค!
  guest = guest + 1
  return <h2>Tea cup for guest #{guest}</h2>
}

export default function TeaSet() {
  return (
    <>
      <Cup />
      <Cup />
      <Cup />
    </>
  )
}

์ด ์ปดํฌ๋„ŒํŠธ๋Š” ์™ธ๋ถ€์—์„œ ์„ ์–ธ๋œ guest ๋ณ€์ˆ˜๋ฅผ ์ฝ๊ณ  ์“ฐ๊ณ  ์žˆ๋‹ค. ์ฆ‰, ์ด ์ปดํฌ๋„ŒํŠธ๋Š” ํ˜ธ์ถœํ•  ๋•Œ๋งˆ๋‹ค ๋‹ค๋ฅธ JSX๊ฐ€ ์ƒ์„ฑ๋œ๋‹ค๋Š” ๋œป์ด๋‹ค! ๊ฒŒ๋‹ค๊ฐ€ ๋‹ค๋ฅธ ์ปดํฌ๋„ŒํŠธ๊ฐ€ guest๋ฅผ ์ฝ์œผ๋ฉด ๋ Œ๋”๋ง๋œ ์‹œ์ ์— ๋”ฐ๋ผ JSX๋„ ๋‹ค๋ฅด๊ฒŒ ์ƒ์„ฑ๋œ๋‹ค.

guest๋ฅผ props๋กœ ์ „๋‹ฌํ•จ์œผ๋กœ์จ ์ด ์ปดํฌ๋„ŒํŠธ๋ฅผ ๊ณ ์น  ์ˆ˜ ์žˆ๋‹ค. ๐Ÿ˜Š

function Cup({ guest }) {
  return <h2>Tea cup for guest #{guest}</h2>
}

export default function TeaSet() {
  return (
    <>
      <Cup guest={1} />
      <Cup guest={2} />
      <Cup guest={3} />
    </>
  )
}

์ด์ œ ์ปดํฌ๋„ŒํŠธ๊ฐ€ ๋ฐ˜ํ™˜ํ•˜๋Š” JSX๋Š” guest props์—๋งŒ ์˜์กดํ•˜๋ฏ€๋กœ ์ˆœ์ˆ˜ํ•˜๋‹ค. ๊ฐ ์ปดํฌ๋„ŒํŠธ๋Š” ๋ Œ๋”๋ง ์ค‘์— ๋‹ค๋ฅธ ์ปดํฌ๋„ŒํŠธ์™€ ์กฐ์œจํ•˜๊ฑฐ๋‚˜ ์˜์กดํ•˜์ง€ ๋ง๊ณ  "์Šค์Šค๋กœ ์ƒ๊ฐ"ํ•˜๊ฒŒ ํ•ด์•ผํ•œ๋‹ค.

local mutation (์ง€์—ญ ๋ณ€์ด) : ์ปดํฌ๋„ŒํŠธ์˜ ์ž‘์€ ๋น„๋ฐ€

์œ„์˜ ์˜ˆ์‹œ์—์„œ๋Š” ์ปดํฌ๋„ŒํŠธ๊ฐ€ ๋ Œ๋”๋งํ•˜๋Š” ๋™์•ˆ ๊ธฐ์กด ๋ณ€์ˆ˜๋ฅผ ๋ณ€๊ฒฝํ•˜๋Š” ๊ฒƒ์ด ๋ฌธ์ œ์˜€๋‹ค. ์ด๋ฅผ "๋ณ€์ด(mutation)" ์ด๋ผ๊ณ  ๋ถ€๋ฅธ๋‹ค. ์ˆœ์ˆ˜ ํ•จ์ˆ˜๋Š” ํ•จ์ˆ˜์˜ ๋ฒ”์œ„๋ฅผ ๋ฒ—์–ด๋‚œ ๋ณ€์ˆ˜๋‚˜ ํ˜ธ์ถœ ์ „์— ์ƒ์„ฑ๋œ ๊ฐ์ฒด๋ฅผ ๋ณ€์ดํ•˜์ง€ ์•Š๋Š”๋‹ค. ๊ทธ๋Ÿฌ๋ฉด ์ˆœ์ˆ˜ํ•˜์ง€ ์•Š๊ธฐ ๋•Œ๋ฌธ์ด๋‹ค.

ํ•˜์ง€๋งŒ ๋ Œ๋”๋งํ•˜๋Š” ๋™์•ˆ '๋ฐฉ๊ธˆ' ์ƒ์„ฑํ•œ ๋ณ€์ˆ˜์™€ ๊ฐ์ฒด๋ฅผ ๋ณ€๊ฒฝํ•˜๋Š” ๊ฒƒ์€ ๊ดœ์ฐฎ๋‹ค. ์ด ์˜ˆ์ œ์—์„œ๋Š” ๋ฐฐ์—ด์„ ์ƒ์„ฑํ•˜๊ณ  ์ด๋ฅผ cups ๋ณ€์ˆ˜์— ํ• ๋‹นํ•œ ๋‹ค์Œ ์ปต 12๊ฐœ๋ฅผ ๊ทธ ์•ˆ์— push ํ•œ๋‹ค.

function Cup({ guest }) {
  return <h2>Tea cup for guest #{guest}</h2>
}

export default function TeaGathering() {
  let cups = []
  for (let i = 1; i < 12; i++) {
    cups.push(<Cup key={i} guest={i} />)
  }

  return cups
}

cups ๋ณ€์ˆ˜๋‚˜ ๋ฐฐ์—ด์ด TeaGathering ํ•จ์ˆ˜ ์™ธ๋ถ€์—์„œ ์ƒ์„ฑ๋˜์—ˆ๋‹ค๋ฉด ์ด๋Š” ํฐ ๋ฌธ์ œ๊ฐ€ ๋  ๊ฒƒ์ด๋‹ค! ํ•ด๋‹น ๋ฐฐ์—ด์— ํ•ญ๋ชฉ์„ ๋ฐ€์–ด ๋„ฃ์Œ์œผ๋กœ์จ ๊ธฐ์กด ๊ฐ์ฒด๋ฅผ ๋ณ€๊ฒฝํ•˜๊ฒŒ ๋  ๊ฒƒ์ด๊ธฐ ๋•Œ๋ฌธ์ด๋‹ค.

ํ•˜์ง€๋งŒ TeaGathering ๋‚ด๋ถ€์—์„œ ๋™์ผํ•œ ๋ Œ๋”๋ง ์ค‘์— ์ƒ์„ฑํ–ˆ๊ธฐ ๋•Œ๋ฌธ์— ๊ดœ์ฐฎ๋‹ค. TeaGathering ์™ธ๋ถ€์˜ ์–ด๋–ค ์ฝ”๋“œ๋„ ์ด๋Ÿฐ ์ผ์ด ์ผ์–ด๋‚ฌ๋‹ค๋Š” ๊ฒƒ์„ ์•Œ ์ˆ˜ ์—†๋‹ค. ์ด๋ฅผ "์ง€์—ญ ๋ณ€์ด(Local Mutation)"์ด๋ผ๊ณ  ํ•˜๋ฉฐ, ์ปดํฌ๋„ŒํŠธ์˜ ์ž‘์€ ๋น„๋ฐ€๊ณผ ๊ฐ™๋‹ค.

์‚ฌ์ด๋“œ ์ดํŽ™ํŠธ๋ฅผ ์ผ์œผํ‚ฌ ์ˆ˜ ์žˆ๋Š” ๊ณณ

ํ•จ์ˆ˜ํ˜• ํ”„๋กœ๊ทธ๋ž˜๋ฐ์€ ์ˆœ์ˆ˜์„ฑ์— ํฌ๊ฒŒ ์˜์กดํ•˜์ง€๋งŒ, ์–ธ์  ๊ฐ€๋Š” ์–ด๋”˜๊ฐ€์—์„œ ๋ฌด์–ธ๊ฐ€๋Š” ๋ฐ”๋€Œ์–ด์•ผ ํ•œ๋‹ค. ์ด๊ฒƒ์ด ๋ฐ”๋กœ ํ”„๋กœ๊ทธ๋ž˜๋ฐ์˜ ํ•ต์‹ฌ์ด๋‹ค! ํ™”๋ฉด ์—…๋ฐ์ดํŠธ, ์• ๋‹ˆ๋ฉ”์ด์…˜ ์‹œ์ž‘, ๋ฐ์ดํ„ฐ ๋ณ€๊ฒฝ๊ณผ ๊ฐ™์€ ์ด๋Ÿฌํ•œ ๋ณ€๊ฒฝ์„ ์‚ฌ์ด๋“œ ์ดํŽ™ํŠธ๋ผ๊ณ  ํ•˜๋ฉฐ, ๋ Œ๋”๋ง ์ค‘์— ์ผ์–ด๋‚˜๋Š” ๊ฒƒ์ด ์•„๋‹ˆ๋ผ "๋ถ€์ˆ˜์ ์œผ๋กœ" ์ผ์–ด๋‚˜๋Š” ์ผ์ด๋‹ค.

React์—์„œ ์‚ฌ์ด๋“œ ์ดํŽ™ํŠธ๋Š” ๋ณดํ†ต ์ด๋ฒคํŠธ ํ•ธ๋“ค๋Ÿฌ์— ์†ํ•œ๋‹ค. ์ด๋ฒคํŠธ ํ•ธ๋“ค๋Ÿฌ๊ฐ€ ์ปดํฌ๋„ŒํŠธ ๋‚ด๋ถ€์— ์ •์˜๋˜์–ด ์žˆ๊ธด ํ•˜์ง€๋งŒ ๋ Œ๋”๋ง ์ค‘์—๋Š” ์‹คํ–‰๋˜์ง€ ์•Š๋Š”๋‹ค! ๋”ฐ๋ผ์„œ ์ด๋ฒคํŠธ ํ•ธ๋“ค๋Ÿฌ๋Š” ์ˆœ์ˆ˜ํ•  ํ•„์š”๊ฐ€ ์—†๋‹ค.

๋‹ค๋ฅธ ๋ชจ๋“  ์˜ต์…˜์„ ๋‹ค ์‚ฌ์šฉํ–ˆ๋Š”๋ฐ๋„ ์‚ฌ์ด๋“œ ์ดํŽ™ํ„ฐ์— ์ ํ•ฉํ•œ ์ด๋ฒคํŠธ ํ•ธ๋“ค๋Ÿฌ๋ฅผ ์ฐพ์„ ์ˆ˜ ์—†๋‹ค๋ฉด, ์ปดํฌ๋„ŒํŠธ์—์„œ useEffect ํ˜ธ์ถœ์„ ํ†ตํ•ด ๋ฐ˜ํ™˜๋œ JSX์— ์ด๋ฒคํŠธ ํ•ธ๋“ค๋Ÿฌ๋ฅผ ์ฒจ๋ถ€ํ•  ์ˆ˜ ์žˆ๋‹ค. ์ด๋ ‡๊ฒŒ ํ•˜๋ฉด ๋‚˜์ค‘์— ๋ Œ๋”๋ง ํ›„ ์‚ฌ์ด๋“œ ์ดํŽ™ํŠธ๊ฐ€ ํ—ˆ์šฉ๋  ๋•Œ React๊ฐ€ ์ด๋ฅผ ์‹คํ–‰ํ•˜๋„๋ก ์ง€์‹œํ•œ๋‹ค. ํ•˜์ง€๋งŒ ์ด ๋ฐฉ๋ฒ•์€ ์ตœํ›„์˜ ์ˆ˜๋‹จ์œผ๋กœ ์‚ฌ์šฉํ•ด์•ผํ•œ๋‹ค.

์š”์•ฝ

  • ์ปดํฌ๋„ŒํŠธ๋Š” ์ˆœ์ˆ˜ํ•ด์•ผ ํ•œ๋‹ค.

    • ์‚ฌ์ด๋“œ ์ดํŽ™ํŠธ๋ฅผ ๋งŒ๋“ค์ง€ ์•Š๋Š”๋‹ค. ํ•จ์ˆ˜๋Š” ์ž…๋ ฅ๋ฐ›์€ ๊ฐ’๋งŒ์„ ๊ฐ€์ง€๊ณ  ๊ฒฐ๊ณผ๋ฅผ ๋ฐ˜ํ™˜ํ•˜๋ฉฐ, ๊ทธ ์™ธ ์–ด๋–ค ์™ธ๋ถ€ ์ƒํƒœ๋„ ๋ณ€๊ฒฝํ•˜์ง€ ์•Š๋Š”๋‹ค.
    • ๋™์ผ ์ž…๋ ฅ, ๋™์ผ ์ถœ๋ ฅ. ๋™์ผํ•œ ์ž…๋ ฅ์— ๋Œ€ํ•ด ์ˆœ์ˆ˜ ํ•จ์ˆ˜๋Š” ์–ธ์ œ๋‚˜ ๋™์ผํ•œ ๊ฒฐ๊ณผ๋ฅผ ์ถœ๋ ฅํ•œ๋‹ค.
  • ์ปดํฌ๋„ŒํŠธ๊ฐ€ ๋ Œ๋”๋ง์— ์‚ฌ์šฉํ•˜๋Š” ์–ด๋– ํ•œ ์ž…๋ ฅ๊ฐ’๋„ ๋ณ€์ดํ•ด์„œ๋Š” ์•ˆ๋œ๋‹ค. ์—ฌ๊ธฐ์—๋Š” props, state ๋ฐ context๊ฐ€ ํฌํ•จ๋œ๋‹ค. ํ™”๋ฉด์„ ์—…๋ฐ์ดํŠธํ•˜๋ ค๋ฉด ๊ธฐ์กด ๊ฐ์ฒด๋ฅผ ๋ณ€์ดํ•˜๋Š” ๋Œ€์‹  setState๋ฅผ ์‚ฌ์šฉํ•˜์ž.
  • ์ปดํฌ๋„ŒํŠธ์˜ ๋กœ์ง์„ ๋ฐ˜ํ™˜ํ•˜๋Š” JSX ์•ˆ์— ํ‘œํ˜„ํ•˜๊ธฐ ์œ„ํ•ด ๋…ธ๋ ฅํ•˜์ž. "๋ฌด์–ธ๊ฐ€๋ฅผ ๋ณ€๊ฒฝ"ํ•ด์•ผ ํ•  ๋•Œ๋Š” ๋ณดํ†ต ์ด๋ฒคํŠธ ํ•ธ๋“ค๋Ÿฌ์—์„œ ์ด ์ž‘์—…์„ ์ˆ˜ํ–‰ํ•˜๊ณ ์ž ํ•  ๊ฒƒ์ด๋‹ค. ์ตœํ›„์˜ ์ˆ˜๋‹จ์œผ๋กœ useEffect๋ฅผ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๋‹ค.
@leedawn
์•ˆ๋…•ํ•˜์„ธ์š”. ์ฃผ๋‹ˆ์–ด ํ”„๋ก ํŠธ์—”๋“œ ๊ฐœ๋ฐœ์ž ์ด์ง€ํ˜œ์ž…๋‹ˆ๋‹ค.