(๋ฒˆ์—ญ) 2024 ๋ฆฌ์•กํŠธ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ

์›๋ฌธ : React Libraries for 2024

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

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

๊ณ„์† ์ฝ๊ธฐ : ๋ฆฌ์•กํŠธ ํŠธ๋ Œ๋“œ

์ด์ œ ๋ฆฌ์•กํŠธ ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜์— ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๋Š” ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ์— ๋Œ€ํ•ด ์ž์„ธํžˆ ์•Œ์•„๋ด…์‹œ๋‹ค.

๋ชฉ์ฐจ

์ƒˆ๋กœ์šด ๋ฆฌ์•กํŠธ ํ”„๋กœ์ ํŠธ ์‹œ์ž‘ํ•˜๊ธฐ

๋ฆฌ์•กํŠธ ์ดˆ๋ณด์ž์—๊ฒŒ ๊ฐ€์žฅ ๋จผ์ € ๋– ์˜ค๋ฅด๋Š” ์งˆ๋ฌธ์€ ๋ฆฌ์•กํŠธ ํ”„๋กœ์ ํŠธ๋ฅผ ์„ค์ •ํ•˜๋Š” ๋ฐฉ๋ฒ•์ž…๋‹ˆ๋‹ค. ์„ ํƒํ•  ์ˆ˜ ์žˆ๋Š” ๋„๊ตฌ๋Š” ๋งŽ์Šต๋‹ˆ๋‹ค. ๋ฆฌ์•กํŠธ ์ปค๋ฎค๋‹ˆํ‹ฐ์—์„œ ๊ฐ€์žฅ ์ธ๊ธฐ ์žˆ๋Š” ๋„๊ตฌ๋Š” ๋‹ค์–‘ํ•œ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ(์˜ˆ: ๋ฆฌ์•กํŠธ)+์˜ตํŠธ์ธ ํƒ€์ž…์Šคํฌ๋ฆฝํŠธ ์กฐํ•ฉ์œผ๋กœ ํ”„๋กœ์ ํŠธ๋ฅผ ์ƒ์„ฑํ•  ์ˆ˜ ์žˆ๋Š” Vite์ž…๋‹ˆ๋‹ค. Vite๋Š” ๋†€๋ผ์šด ์„ฑ๋Šฅ์„ ๋ณด์—ฌ์ค๋‹ˆ๋‹ค.

๊ณ„์† ์ฝ๊ธฐ : ์›น ์‚ฌ์ดํŠธ ๋ฐ ์›น ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜์— ๋Œ€ํ•ด ์ž์„ธํžˆ ์•Œ์•„๋ณด๊ธฐ

์ด๋ฏธ ๋ฆฌ์•กํŠธ์— ์ต์ˆ™ํ•˜๋‹ค๋ฉด ๊ฐ€์žฅ ์ธ๊ธฐ ์žˆ๋Š” (๋ฉ”ํƒ€) ํ”„๋ ˆ์ž„์›Œํฌ ์ค‘ ํ•˜๋‚˜์ธ Next.js๋ฅผ Vite ๋Œ€์‹  ์„ ํƒํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ์ด ํ”„๋ ˆ์ž„์›Œํฌ๋Š” ๋ฆฌ์•กํŠธ๋ฅผ ๊ธฐ๋ฐ˜์œผ๋กœ ๊ตฌ์ถ•๋˜์—ˆ์œผ๋ฏ€๋กœ ๋ฆฌ์•กํŠธ์˜ ๊ธฐ๋ณธ ์‚ฌํ•ญ์— ๋Œ€ํ•ด ์•Œ๊ณ  ์žˆ์–ด์•ผ ํ•ฉ๋‹ˆ๋‹ค. ์ด ๋ถ„์•ผ์—์„œ ์ธ๊ธฐ ์žˆ๋Š” ๋Œ€์•ˆ์€ Remix์ž…๋‹ˆ๋‹ค.

๊ณ„์† ์ฝ๊ธฐ : ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ ๋˜๋Š” ํ”„๋ ˆ์ž„์›Œํฌ๋กœ์„œ ๋ฆฌ์•กํŠธ๋ฅผ ๋ฐฐ์šฐ๋Š” ๋ฐฉ๋ฒ•

Next.js๋Š” ์ฒ˜์Œ์—๋Š” ์„œ๋ฒ„ ์‚ฌ์ด๋“œ ๋ Œ๋”๋ง(์›น ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜)์— ์‚ฌ์šฉ๋˜์—ˆ์ง€๋งŒ, ๋‹ค๋ฅธ ๋ Œ๋”๋ง ํŒจํ„ด์— ์ด์–ด ์ •์  ์‚ฌ์ดํŠธ ์ƒ์„ฑ(SSG)์—๋„ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. Next.js์— ๊ฐ€์žฅ ์ตœ๊ทผ์— ์ถ”๊ฐ€๋œ ๊ฒƒ์€ 2023๋…„๋ถ€ํ„ฐ ๋ฆฌ์•กํŠธ ์ปดํฌ๋„ŒํŠธ๋ฅผ ํด๋ผ์ด์–ธํŠธ์—์„œ ์„œ๋ฒ„๋กœ ์ด๋™ํ•˜์—ฌ ํŒจ๋Ÿฌ๋‹ค์ž„ ์ „ํ™˜์— ๊ธฐ์—ฌํ•˜๋Š” ๋ฆฌ์•กํŠธ ์„œ๋ฒ„ ์ปดํฌ๋„ŒํŠธ์ž…๋‹ˆ๋‹ค.

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

๊ณ„์† ์ฝ๊ธฐ : ๋ฆฌ์•กํŠธ ํ”„๋กœ์ ํŠธ๋ฅผ ์‹œ์ž‘ํ•˜๋Š” ๋ฐฉ๋ฒ•

Vite์™€ ๊ฐ™์€ ๋„๊ตฌ๊ฐ€ ์–ด๋–ป๊ฒŒ ์ž‘๋™ํ•˜๋Š”์ง€ ์ดํ•ดํ•˜๊ณ  ์‹ถ๋‹ค๋ฉด ์ง์ ‘ ๋ฆฌ์•กํŠธ ํ”„๋กœ์ ํŠธ๋ฅผ ์„ธํŒ…ํ•ด ๋ณด์„ธ์š”. ์ž๋ฐ”์Šคํฌ๋ฆฝํŠธ๊ฐ€ ํฌํ•จ๋œ HTML ํ”„๋กœ์ ํŠธ๋กœ ์‹œ์ž‘ํ•˜์—ฌ ์ง€์› ๋„๊ตฌ(์˜ˆ: Webpack, Babel)์™€ ํ•จ๊ป˜ ๋ฆฌ์•กํŠธ๋ฅผ ์ง์ ‘ ์ถ”๊ฐ€ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ํŠนํžˆ Vite๊ฐ€ Webpack์˜ ๊ณ„์Šน์ž๊ฐ€ ๋˜์—ˆ๊ธฐ ๋•Œ๋ฌธ์— ์ผ์ƒ์ ์ธ ์ž‘์—…์—์„œ ๊ผญ ๋‹ค๋ค„์•ผ ํ•˜๋Š” ๊ฒƒ์€ ์•„๋‹ˆ์ง€๋งŒ, ๊ธฐ๋ณธ ๋„๊ตฌ์— ๋Œ€ํ•ด ์•Œ์•„๊ฐ€๋Š” ๊ฒƒ์€ ํ›Œ๋ฅญํ•œ ํ•™์Šต ๊ฒฝํ—˜์ด ๋  ๊ฒƒ์ž…๋‹ˆ๋‹ค.

๋ฆฌ์•กํŠธ์˜ ๋ฒ ํ…Œ๋ž‘์ด๊ณ  ์ƒˆ๋กœ์šด ๊ฒƒ์„ ์‹œ๋„ํ•ด๋ณด๊ณ  ์‹ถ๋‹ค๋ฉด Nitro ๋˜๋Š” Waku๋ฅผ ํ™•์ธํ•ด ๋ณด์„ธ์š”. ํ›„์ž๋Š” Zustand์˜ ๊ฐœ๋ฐœ์ž๊ฐ€ ๋งŒ๋“  ๊ฒƒ์œผ๋กœ, ๋ฆฌ์•กํŠธ ์„œ๋ฒ„ ์ปดํฌ๋„ŒํŠธ๋ฅผ ์ง€์›ํ•ฉ๋‹ˆ๋‹ค.

์ถ”์ฒœ

  • ํด๋ผ์ด์–ธํŠธ ์‚ฌ์ด๋“œ ๋ Œ๋”๋ง ๋ฆฌ์•กํŠธ ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜์„ ์œ„ํ•œ Vite
  • ์„œ๋ฒ„ ์‚ฌ์ด๋“œ ๋ Œ๋”๋ง ๋ฆฌ์•กํŠธ ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜์„ ์œ„ํ•œ Next.js
  • ์ •์  ์‚ฌ์ด๋“œ์—์„œ ์ƒ์„ฑ๋œ ๋ฆฌ์•กํŠธ ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜์„ ์œ„ํ•œ Astro
  • ์„ ํƒ์  ํ•™์Šต ๊ฒฝํ—˜: ๋ฆฌ์•กํŠธ ํ”„๋กœ์ ํŠธ ์ฒ˜์Œ๋ถ€ํ„ฐ ๋งŒ๋“ค์–ด๋ณด๊ธฐ

๋ฆฌ์•กํŠธ๋ฅผ ์œ„ํ•œ ํŒจํ‚ค์ง€ ๋งค๋‹ˆ์ €

์ž๋ฐ”์Šคํฌ๋ฆฝํŠธ ์ƒํƒœ๊ณ„(์ฆ‰, ๋ฆฌ์•กํŠธ)์—์„œ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ(์˜์กด์„ฑ, ๋…ธ๋“œ ํŒจํ‚ค์ง€)๋ฅผ ์„ค์น˜ํ•˜๋Š” ๋ฐ ๊ฐ€์žฅ ๋„๋ฆฌ ์‚ฌ์šฉ๋˜๋Š” ํŒจํ‚ค์ง€ ๊ด€๋ฆฌ์ž๋Š” npm์œผ๋กœ, ๋ชจ๋“  Node.js ์„ค์น˜์™€ ํ•จ๊ป˜ ์ œ๊ณต๋˜๊ธฐ ๋•Œ๋ฌธ์ž…๋‹ˆ๋‹ค. ํ•˜์ง€๋งŒ yarn๊ณผ pnpm๋„ ํ›Œ๋ฅญํ•œ ๋Œ€์•ˆ์ด๋ฉฐ, ํŠนํžˆ ํ›„์ž๋Š” ๋” ํฐ ์„ฑ๋Šฅ ํ–ฅ์ƒ์„ ์ œ๊ณตํ•ฉ๋‹ˆ๋‹ค.

๊ณ„์† ์ฝ๊ธฐ : ์›น ๊ฐœ๋ฐœ์„ ์œ„ํ•œ Mac ์„ค์ •

์„œ๋กœ ์˜์กดํ•˜๊ฑฐ๋‚˜ ๊ณตํ†ต๋œ ์‚ฌ์šฉ์ž ์ •์˜ UI ์ปดํฌ๋„ŒํŠธ ์„ธํŠธ๋ฅผ ๊ณต์œ ํ•˜๋Š” ์—ฌ๋Ÿฌ ๊ฐœ์˜ ๋ฆฌ์•กํŠธ ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜์„ ๋งŒ๋“œ๋Š” ๊ฒฝ์šฐ ๋ชจ๋…ธ๋ ˆํฌ๋ผ๋Š” ๊ฐœ๋…์„ ํ™•์ธํ•ด ๋ณผ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ์•ž์„œ ์–ธ๊ธ‰ํ•œ ๋ชจ๋“  ํŒจํ‚ค์ง€ ๊ด€๋ฆฌ์ž๋Š” ์ž์ฒด ์ž‘์—… ๊ณต๊ฐ„ ๊ธฐ๋Šฅ์„ ์‚ฌ์šฉํ•˜์—ฌ ๋ชจ๋…ธ๋ ˆํฌ๋ฅผ ์ƒ์„ฑํ•  ์ˆ˜ ์žˆ์ง€๋งŒ, ๊ฐœ์ธ์ ์œผ๋กœ๋Š” yarn ๋˜๋Š” pnpm์„ ์‚ฌ์šฉํ•˜๋Š” ๊ฒƒ์ด ๊ฐ€์žฅ ์ข‹์€ ๊ฐœ๋ฐœ์ž ๊ฒฝํ—˜์ด์—ˆ์Šต๋‹ˆ๋‹ค. Turborepo์™€ ๊ฐ™์€ ๋ชจ๋…ธ๋ ˆํฌ ํŒŒ์ดํ”„๋ผ์ธ ๋„๊ตฌ์™€ ํ•จ๊ป˜ ์‚ฌ์šฉํ•˜๋ฉด ์™„๋ฒฝํ•œ ๋ชจ๋…ธ๋ ˆํฌ ๊ฒฝํ—˜์ด ๋  ๊ฒƒ์ž…๋‹ˆ๋‹ค.

๊ณ„์† ์ฝ๊ธฐ : ๋ชจ๋…ธ๋ ˆํฌ ์„ค์ •

์ถ”์ฒœ

  • ํ•˜๋‚˜์˜ ํŒจํ‚ค์ง€ ๊ด€๋ฆฌ์ž๋ฅผ ์„ ํƒํ•˜๊ณ  ๊ทธ๊ฒƒ๋งŒ ์‚ฌ์šฉํ•˜์„ธ์š”.

    • ๊ธฐ๋ณธ์ ์ด๊ณ  ๊ฐ€์žฅ ๋„๋ฆฌ ์‚ฌ์šฉ๋˜๋Š” -> npm
    • ์„ฑ๋Šฅ์€ ํ–ฅ์ƒ๋˜์—ˆ์ง€๋งŒ, ์ƒ๋‹นํžˆ ์ƒˆ๋กญ๊ณ  ๋Œ€์ค‘์ ์ด์ง€ ์•Š์€ -> pnpm
  • ๋ชจ๋…ธ๋ ˆํฌ๊ฐ€ ํ•„์š”ํ•œ ๊ฒฝ์šฐ, Turborepo๋ฅผ ํ™•์ธํ•˜์„ธ์š”(ํŠœํ† ๋ฆฌ์–ผ์„ ๋ณด์„ธ์š”).

๋ฆฌ์•กํŠธ ์ƒํƒœ ๊ด€๋ฆฌ

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

๊ณ„์† ์ฝ๊ธฐ : ์–ธ์ œ useState ์™€ useReducer๋ฅผ ์‚ฌ์šฉํ•ด์•ผ ํ•˜๋Š”์ง€ ์•Œ์•„๋ณด๊ธฐ

๋ฆฌ์•กํŠธ์˜ useState/useReducer ํ›…์„ ์‚ฌ์šฉํ•˜์—ฌ ์ปดํฌ๋„ŒํŠธ์— ํ•จ๊ป˜ ๋ฐฐ์น˜ํ•˜๊ฑฐ๋‚˜, ๋ฆฌ์•กํŠธ์˜ useContext ํ›…๊ณผ ๊ฒฐํ•ฉํ•˜์—ฌ ์ „์—ญ์ ์œผ๋กœ ๊ด€๋ฆฌํ•  ์ˆ˜๋„ ์žˆ์Šต๋‹ˆ๋‹ค. ์„ธ ๊ฐ€์ง€ ๋ฆฌ์•กํŠธ ํ›…์„ ํ†ตํ•ด ๊ฐœ๋ฐœ์ž๋Š” ๊ฐ•๋ ฅํ•œ ์ƒํƒœ ๊ด€๋ฆฌ๋ฅผ ๋ฆฌ์•กํŠธ์—์„œ ๊ตฌํ˜„ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

๊ณ„์† ์ฝ๊ธฐ : useState/useReducer๋ฅผ useContext์™€ ๊ฒฐํ•ฉํ•˜๋Š” ๋ฐฉ๋ฒ• ์•Œ์•„๋ณด๊ธฐ

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

Zustand๊ฐ€ ์ปค๋ฎค๋‹ˆํ‹ฐ์—์„œ ์‚ฌ์‹ค์ƒ ํ‘œ์ค€์ด ๋˜์—ˆ๋‹ค๊ณ  ๋งํ•˜์ง€๋งŒ, ์ƒํƒœ ๊ด€๋ฆฌ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ๊ฐ€ ํ•„์š”ํ•˜๋‹ค๋ฉด ์—ฌ์ „ํžˆ ๊ฐ€์žฅ ์ธ๊ธฐ ์žˆ๋Š” ์ƒํƒœ ๊ด€๋ฆฌ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ์ธ Redux๋ฅผ ๋นผ๋†“์„ ์ˆ˜ ์—†์„ ๊ฒƒ์ž…๋‹ˆ๋‹ค. ์ €๋Š” Zustand์˜ ๋‹จ์ˆœ์„ฑ์„ ์ข‹์•„ํ•˜๊ธฐ ๋•Œ๋ฌธ์— Redux๋ฅผ ์ง€๋‚œ ๋ช‡ ๋…„๊ฐ„์˜ ๊ฐœ์ธ์ ์ธ ํ”„๋ฆฌ๋žœ์„œ ํ”„๋กœ์ ํŠธ์—์„œ ์‚ฌ์šฉํ•˜์ง€๋Š” ์•Š์•˜์ง€๋งŒ, Redux์™€ ํ•จ๊ป˜ ์ œ๊ณต๋˜๋Š” ์˜ค๋ž˜๋œ ๋ฆฌ์•กํŠธ ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜์„ ๋งŽ์ด ์ฐพ์„ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

๊ณ„์† ์ฝ๊ธฐ : Redux ํŠœํ† ๋ฆฌ์–ผ(Redux Toolkit ์ œ์™ธ)

Redux๋ฅผ ์‚ฌ์šฉํ•˜์‹ ๋‹ค๋ฉด Redux Toolkit๋„ ๊ผญ ํ™•์ธํ•ด ๋ณด์„ธ์š”. ๊ทธ๋ฆฌ๊ณ  ์ƒํƒœ ๋จธ์‹ ์— ๊ด€์‹ฌ์ด ์žˆ๋‹ค๋ฉด XState ๋˜๋Š” Zag๋ฅผ ํ™•์ธํ•ด ๋ณด์„ธ์š”. ์ „์—ญ ์Šคํ† ์–ด๊ฐ€ ํ•„์š”ํ•˜์ง€๋งŒ Zustand๋‚˜ Redux๊ฐ€ ๋งˆ์Œ์— ๋“ค์ง€ ์•Š๋Š”๋‹ค๋ฉด Jotai, Recoil ๋˜๋Š” Nano Stores์™€ ๊ฐ™์€ ๋‹ค๋ฅธ ์ธ๊ธฐ ์žˆ๋Š” ๋กœ์ปฌ ์ƒํƒœ ๊ด€๋ฆฌ ์†”๋ฃจ์…˜์„ ํ™•์ธํ•ด ๋ณด์„ธ์š”.

์ถ”์ฒœ

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

๋ฆฌ์•กํŠธ ๋ฐ์ดํ„ฐ ํŽ˜์นญ

UI์˜ ์ƒํƒœ๋Š” ๋ฆฌ์•กํŠธ ๋‚ด์žฅ ํ›…์œผ๋กœ๋„ ์ถฉ๋ถ„ํ•˜์ง€๋งŒ, ์›๊ฒฉ ๋ฐ์ดํ„ฐ(์ฆ‰, ๋ฐ์ดํ„ฐ ํŽ˜์นญ)์— ๋Œ€ํ•œ ์ƒํƒœ ๊ด€๋ฆฌ(์บ์‹ฑ)์— ๊ด€ํ•ด์„œ๋Š” TanStack Query(์ด์ „์˜ React Query)์™€ ๊ฐ™์€ ์ „์šฉ ๋ฐ์ดํ„ฐ ํŽ˜์นญ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ๋ฅผ ์‚ฌ์šฉํ•˜๋Š” ๊ฒƒ์„ ๊ถŒ์žฅํ•ฉ๋‹ˆ๋‹ค.

TanStack Query ์ž์ฒด๋Š” ์ƒํƒœ ๊ด€๋ฆฌ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ๋กœ ๊ฐ„์ฃผ๋˜์ง€ ์•Š์ง€๋งŒ, ์ฃผ๋กœ API์—์„œ ์›๊ฒฉ ๋ฐ์ดํ„ฐ๋ฅผ ๊ฐ€์ ธ์˜ค๋Š” ๋ฐ ์‚ฌ์šฉ๋˜๊ธฐ ๋•Œ๋ฌธ์— ์›๊ฒฉ ๋ฐ์ดํ„ฐ์˜ ๋ชจ๋“  ์ƒํƒœ ๊ด€๋ฆฌ(์˜ˆ: ์บ์‹ฑ, ๋‚™๊ด€์  ์—…๋ฐ์ดํŠธ)๋ฅผ ๋Œ€์‹  ์ฒ˜๋ฆฌํ•ด ์ค๋‹ˆ๋‹ค.

๊ณ„์† ์ฝ๊ธฐ : TanStack Query๊ฐ€ ๋‚ด๋ถ€์—์„œ ์–ด๋–ป๊ฒŒ ์ž‘๋™ํ•˜๋Š”์ง€ ์•Œ์•„๋ณด๊ธฐ

TanStack Query๋Š” REST API๋ฅผ ์‚ฌ์šฉํ•˜๋„๋ก ์„ค๊ณ„๋˜์—ˆ์Šต๋‹ˆ๋‹ค. ํ•˜์ง€๋งŒ ์š”์ฆ˜์€ GraphQL๋„ ์ง€์›ํ•ฉ๋‹ˆ๋‹ค. ๊ทธ๋Ÿฌ๋‚˜ ๋ฆฌ์•กํŠธ ํ”„๋ŸฐํŠธ์—”๋“œ๋ฅผ ์œ„ํ•œ ๋ณด๋‹ค ์ „์šฉ์ ์ธ GraphQL ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ๋ฅผ ์ฐพ๊ณ  ์žˆ๋‹ค๋ฉด ์ธ๊ธฐ ์žˆ๋Š” Apollo Client๋‚˜ ๊ฐ€๋ฒผ์šด urql ๋˜๋Š” Facebook์—์„œ ์ œ๊ณตํ•˜๋Š” Relay ์ค‘ ํ•˜๋‚˜๋ฅผ ํ™•์ธํ•ด ๋ณด์„ธ์š”.

๊ณ„์† ์ฝ๊ธฐ : ๋กœ์ปฌ ๋ฐ ์›๊ฒฉ ๋ฐ์ดํ„ฐ์— ๋Œ€ํ•œ ๋ฆฌ์•กํŠธ ์ƒํƒœ์— ๊ด€ํ•œ ๋ชจ๋“  ๊ฒƒ

์ด๋ฏธ Redux๋ฅผ ์‚ฌ์šฉ ์ค‘์ด๊ณ  Redux์—์„œ ํ†ตํ•ฉ ์ƒํƒœ ๊ด€๋ฆฌ์™€ ํ•จ๊ป˜ ๋ฐ์ดํ„ฐ ํŽ˜์นญ์„ ์ถ”๊ฐ€ํ•˜๋ ค๋Š” ๊ฒฝ์šฐ, TanStack Query๋ฅผ ์ถ”๊ฐ€ํ•˜๋Š” ๋Œ€์‹  ๋ฐ์ดํ„ฐ ํŽ˜์นญ์„ Redux์— ๊น”๋”ํ•˜๊ฒŒ ํ†ตํ•ฉํ•˜๋Š” RTK Query๋ฅผ ํ™•์ธํ•ด ๋ณผ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

๋งˆ์ง€๋ง‰์œผ๋กœ, ํ”„๋ŸฐํŠธ์—”๋“œ์™€ ๋ฐฑ์—”๋“œ(๋‘˜ ๋‹ค ํƒ€์ž…์Šคํฌ๋ฆฝํŠธ)๋ฅผ ์ œ์–ดํ•˜๋Š” ๊ฒฝ์šฐ, ์—”๋“œํˆฌ์—”๋“œ ํƒ€์ž… ์•ˆ์ „ํ•œ API๋ฅผ ์œ„ํ•ด tRPC๋ฅผ ํ™•์ธํ•ด ๋ณด์„ธ์š”. ์ €๋Š” ์ง€๋‚œ 1๋…„ ๋™์•ˆ ์ด ๋„๊ตฌ๋ฅผ ์‚ฌ์šฉํ•ด ์™”๋Š”๋ฐ ์ƒ์‚ฐ์„ฑ ํ–ฅ์ƒ๊ณผ DX์— ์—„์ฒญ๋‚œ ๋„์›€์ด ๋˜์—ˆ์Šต๋‹ˆ๋‹ค. TanStack Query์™€ ๊ฒฐํ•ฉํ•˜์—ฌ ๋ฐ์ดํ„ฐ ํŽ˜์นญ๊ณผ ๊ด€๋ จ๋œ ๋ชจ๋“  ๊ธฐ๋Šฅ์„ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ์œผ๋ฉฐ, ๋™์‹œ์— ํƒ€์ž…์ด ์ง€์ •๋œ ํ•จ์ˆ˜๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ํ”„๋ŸฐํŠธ์—”๋“œ์—์„œ ๋ฐฑ์—”๋“œ๋ฅผ ํ˜ธ์ถœํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

๊ณ„์† ์ฝ๊ธฐ : E2E ํƒ€์ž… ์•ˆ์ „์„ฑ์„ ๊ฐ–์ถ˜ ์ฒซ ๋ฒˆ์งธ tRPC ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜ ๋งŒ๋“ค๊ธฐ

์ถ”์ฒœ

๋ฆฌ์•กํŠธ ๋ผ์šฐํ„ฐ๋ฅผ ํ†ตํ•œ ๋ผ์šฐํŒ…

Next.js์™€ ๊ฐ™์€ ๋ฆฌ์•กํŠธ ํ”„๋ ˆ์ž„์›Œํฌ๋Š” ์ด๋ฏธ ๋ผ์šฐํŒ…์ด ์ฒ˜๋ฆฌ๋˜์–ด ์žˆ์Šต๋‹ˆ๋‹ค. ๊ทธ๋Ÿฌ๋‚˜ ํ”„๋ ˆ์ž„์›Œํฌ ์—†์ด ํด๋ผ์ด์–ธํŠธ ์ธก ๋ Œ๋”๋ง์—๋งŒ ๋ฆฌ์•กํŠธ๋ฅผ ์‚ฌ์šฉํ•˜๋Š” ๊ฒฝ์šฐ(์˜ˆ: SSR์ด ์—†๋Š” Vite), ๊ฐ€์žฅ ๊ฐ•๋ ฅํ•˜๊ณ  ์ธ๊ธฐ ์žˆ๋Š” ๋ผ์šฐํŒ… ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ๋Š” React Router์ž…๋‹ˆ๋‹ค. ์™„์ „ํ•œ ํƒ€์ž…์Šคํฌ๋ฆฝํŠธ ์ง€์›์„ ์—ผ๋‘์— ๋‘” ์ƒˆ๋กœ์šด ๋Œ€์•ˆ์œผ๋กœ TanStack Router๊ฐ€ ์žˆ์Šต๋‹ˆ๋‹ค.

๊ณ„์† ์ฝ๊ธฐ : React Router ์‚ฌ์šฉ๋ฒ• ์•Œ์•„๋ณด๊ธฐ

๋ฆฌ์•กํŠธ ๋ผ์šฐํ„ฐ์™€ ํ•จ๊ป˜ ๋ฆฌ์•กํŠธ์—์„œ ํด๋ผ์ด์–ธํŠธ ์ธก ๋ผ์šฐํŒ…์„ ์‚ฌ์šฉํ•˜๋Š” ๊ฒฝ์šฐ, ๋ผ์šฐํŠธ ์ˆ˜์ค€์—์„œ ์ฝ”๋“œ ๋ถ„ํ• ์„ ๋„์ž…ํ•˜๋Š” ๊ฒƒ์€ ๊ทธ๋ฆฌ ์–ด๋ ค์šด ์ผ์ด ์•„๋‹™๋‹ˆ๋‹ค. ์ด๋Ÿฐ ์ข…๋ฅ˜์˜ ์ตœ์ ํ™”๋ฅผ ๋„์ž…ํ•˜๋Š” ๊ฒฝ์šฐ, React.lazy()๋ฅผ @loadable/component๋กœ ๋Œ€์ฒดํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

๊ณ„์† ์ฝ๊ธฐ : React Router๋กœ ์ง€์—ฐ ๋กœ๋”ฉ ๋ฐฐ์šฐ๊ธฐ

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

์ถ”์ฒœ

  • ๊ฐ€์žฅ ์ธ๊ธฐ ์žˆ๋Š” ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ๋Š” React Router
  • ์š”์ฆ˜ ๋– ์˜ค๋ฅด๋Š” ๊ฒƒ์€ TanStack Router

    • ์ฃผ๋กœ ์ตœ๊ณ  ์ˆ˜์ค€์˜ TS ์ง€์› ๋•Œ๋ฌธ์ž…๋‹ˆ๋‹ค.

๋ฆฌ์•กํŠธ CSS ์Šคํƒ€์ผ๋ง

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

๊ณ„์† ์ฝ๊ธฐ : ๋ฆฌ์•กํŠธ CSS ์Šคํƒ€์ผ๋ง(์ข…ํ•ฉ ํŠœํ† ๋ฆฌ์–ผ)

๋ฆฌ์•กํŠธ ์ดˆ๋ณด์ž๋Š” JSX์—์„œ ์Šคํƒ€์ผ ๊ฐ์ฒด๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ์ธ๋ผ์ธ ์Šคํƒ€์ผ๊ณผ ๊ธฐ๋ณธ CSS๋กœ ์‹œ์ž‘ํ•ด๋„ ๊ดœ์ฐฎ์Šต๋‹ˆ๋‹ค. ํ•˜์ง€๋งŒ ์‹ค์ œ ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜์—๋Š” ๊ฑฐ์˜ ์‚ฌ์šฉํ•˜์ง€ ์•Š๋Š”๊ฒƒ์ด ์ข‹์Šต๋‹ˆ๋‹ค.

const Headline = ({ title }) => <h1 style={{ color: 'blue' }}>{title}</h1>;

์ธ๋ผ์ธ ์Šคํƒ€์ผ์€ ๋ฆฌ์•กํŠธ์˜ JSX์—์„œ ์ž๋ฐ”์Šคํฌ๋ฆฝํŠธ๋กœ ์Šคํƒ€์ผ์„ ๋™์ ์œผ๋กœ ์ถ”๊ฐ€ํ•˜๋Š” ๋ฐ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ์ง€๋งŒ, ์™ธ๋ถ€ CSS ํŒŒ์ผ์€ ๋ฆฌ์•กํŠธ ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜์˜ ๋‚˜๋จธ์ง€ ์Šคํƒ€์ผ์„ ๋ชจ๋‘ ๋‹ด์„ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

import './Headline.css';

const Headline = ({ title }) => (
  <h1 className="headline" style={{ color: 'blue' }}>
    {title}
  </h1>
);

์• ํ”Œ๋ฆฌ์ผ€์ด์…˜์˜ ํฌ๊ธฐ๊ฐ€ ์ปค์ง€๋ฉด ๋‹ค๋ฅธ ์Šคํƒ€์ผ๋ง ๋ฐฉ๋ฒ•์„ ํ™•์ธํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

๋จผ์ €, ์—ฌ๋Ÿฌ CSS-in-CSS ์†”๋ฃจ์…˜ ์ค‘ ํ•˜๋‚˜์ธ CSS Module์„ ์‚ดํŽด๋ณผ ๊ฒƒ์„ ๊ถŒ์žฅํ•ฉ๋‹ˆ๋‹ค. CSS Module์„ ์‚ฌ์šฉํ•˜๋ฉด CSS๋ฅผ ์ปดํฌ๋„ŒํŠธ์™€ ํ•จ๊ป˜ ๋ฐฐ์น˜๋œ ๋ชจ๋“ˆ๋กœ ์บก์Аํ™”ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ์ด๋Š” ์Šคํƒ€์ผ์ด ๋‹ค๋ฅธ ์ปดํฌ๋„ŒํŠธ๋กœ ์‹ค์ˆ˜๋กœ ์œ ์ถœ๋˜๋Š” ๊ฒƒ์„ ๋ฐฉ์ง€ํ•ฉ๋‹ˆ๋‹ค.

import styles from './style.module.css';

const Headline = ({ title }) => <h1 className={styles.headline}>{title}</h1>;

๋‘ ๋ฒˆ์งธ๋กœ, ๋ฆฌ์•กํŠธ๋ฅผ ์œ„ํ•œ ๋งŽ์€ CSS-in-JS ์†”๋ฃจ์…˜ ์ค‘ ํ•˜๋‚˜์ธ Styled Components๋ฅผ ์†Œ๊ฐœํ•˜๊ณ ์ž ํ•ฉ๋‹ˆ๋‹ค(๋” ์ด์ƒ ๊ถŒ์žฅํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค). ์ด ์ ‘๊ทผ ๋ฐฉ์‹์€ Styled-Components(๋˜๋Š” emotion๊ณผ ๊ฐ™์€ ๋Œ€์•ˆ)๋ผ๋Š” ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ๋ฅผ ํ†ตํ•ด ์ œ๊ณต๋˜๋Š”๋ฐ, ์ด ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ๋Š” ์ž๋ฐ”์Šคํฌ๋ฆฝํŠธ๋กœ ์ƒ์„ฑ๋œ ์Šคํƒ€์ผ๋ง์„ ๊ฐ™์€ ํŒŒ์ผ์˜ ๋ฆฌ์•กํŠธ ์ปดํฌ๋„ŒํŠธ ์˜† ๋˜๋Š” ๊ฐ™์€ ์œ„์น˜์— ์žˆ๋Š” ํŒŒ์ผ์— ๋ฐฐ์น˜ํ•ฉ๋‹ˆ๋‹ค.

import styled from 'styled-components';

const BlueHeadline = styled.h1`
  color: blue;
`;

const Headline = ({ title }) => <BlueHeadline>{title}</BlueHeadline>;

๊ณ„์† ์ฝ๊ธฐ : Styled Components ๋ชจ๋ฒ” ์‚ฌ๋ก€

์…‹์งธ, ๊ฐ€์žฅ ์ธ๊ธฐ ์žˆ๋Š” Utility-First-CSS ์†”๋ฃจ์…˜์œผ๋กœ Tailwind CSS๋ฅผ ์ถ”์ฒœํ•˜๊ณ  ์‹ถ์Šต๋‹ˆ๋‹ค. ์ด ์†”๋ฃจ์…˜์€ ์‚ฌ์ „ ์ •์˜๋œ CSS ํด๋ž˜์Šค์™€ ํ•จ๊ป˜ ์ œ๊ณต๋ฉ๋‹ˆ๋‹ค. ์ด๋ฅผ ํ†ตํ•ด ๊ฐœ๋ฐœ์ž์˜ ํšจ์œจ์„ฑ์„ ๋†’์ด๊ณ  ๋ฆฌ์•กํŠธ ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜์˜ ๋””์ž์ธ ์‹œ์Šคํ…œ์„ ๊ฐ„์†Œํ™”ํ•  ์ˆ˜ ์žˆ์ง€๋งŒ, ๋ชจ๋“  ํด๋ž˜์Šค๋ฅผ ์•Œ์•„์•ผ ํ•˜๊ณ  ๋งŽ์€ CSS ํด๋ž˜์Šค์˜ ์žฅํ™ฉํ•œ ์ธ๋ผ์ด๋‹์ด ํ•„์š”ํ•˜๋‹ค๋Š” ๋‹จ์ ์ด ์žˆ์Šต๋‹ˆ๋‹ค.

const Headline = ({ title }) => <h1 className="text-blue-700">{title}</h1>;

CSS-in-CSS๋ฅผ ์„ ํƒํ• ์ง€, Utility-First-CSS๋ฅผ ์„ ํƒํ• ์ง€๋Š” ์‚ฌ์šฉ์ž์—๊ฒŒ ๋‹ฌ๋ ค ์žˆ์Šต๋‹ˆ๋‹ค. ์ตœ๊ทผ์˜ ์ถ”์„ธ๋Š” Tailwind CSS๋ฅผ ์‚ฌ์šฉํ•œ Utility-First-CSS์ž…๋‹ˆ๋‹ค. CSS-in-JS ์†”๋ฃจ์…˜์€ ์„œ๋ฒ„ ์ธก ํ™˜๊ฒฝ๊ณผ ๊ด€๋ จ๋œ ๋ฌธ์ œ๋กœ ์ธํ•ด ๋” ์ด์ƒ ์ธ๊ธฐ๊ฐ€ ์—†์Šต๋‹ˆ๋‹ค. ๋งˆ์ง€๋ง‰์œผ๋กœ ํ•œ ๊ฐ€์ง€ ํžŒํŠธ๋ฅผ ๋“œ๋ฆฌ์ž๋ฉด, ๋ฆฌ์•กํŠธ์—์„œ className์„ ์กฐ๊ฑด๋ถ€๋กœ ์ ์šฉํ•˜๋ ค๋ฉด clsx์™€ ๊ฐ™์€ ์œ ํ‹ธ๋ฆฌํ‹ฐ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ๋ฅผ ์‚ฌ์šฉํ•˜์„ธ์š”.

์ถ”์ฒœ

  • Utility-First-CSS (๊ฐ€์žฅ ์ธ๊ธฐ ์žˆ์Œ)

    • ์˜ˆ: Tailwind CSS
  • CSS-in-CSS

    • ์˜ˆ: CSS Modules
  • CSS-in-JS(๊ฐœ์ธ์ ์œผ๋กœ๋Š” ์„œ๋ฒ„ ์‚ฌ์ด๋“œ ํ™˜๊ฒฝ์—์„œ์˜ ์„ฑ๋Šฅ ๋ฐ ๊ธฐํƒ€ ๋ฌธ์ œ๋กœ ์ธํ•ด ๋Ÿฐํƒ€์ž„ CSS-in-JS๋ฅผ ๋” ์ด์ƒ ๊ถŒ์žฅํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค.)

    • ์˜ˆ: Styled Components ๋˜๋Š” Facebook์˜ StyleX
  • CSS-in-TS(ํƒ€์ž…์Šคํฌ๋ฆฝํŠธ ๋ฐ ์„œ๋ฒ„ ์‚ฌ์ด๋“œ ๋ Œ๋”๋ง ์ง€์›)

๋ฆฌ์•กํŠธ UI ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ

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

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

  • Material UI(MUI)(์—ฌ์ „ํžˆ ํ”„๋ฆฌ๋žœ์„œ ํ”„๋กœ์ ํŠธ์—์„œ ๊ฐ€์žฅ ์ธ๊ธฐ ์žˆ์Œ)
  • Mantine UI (2022๋…„์— ๊ฐ€์žฅ ์ธ๊ธฐ ์žˆ์Œ)
  • Chakra UI (2021๋…„์— ๊ฐ€์žฅ ์ธ๊ธฐ ์žˆ์Œ)
  • NextUI (React Aria ๊ธฐ๋ฐ˜)
  • Park UI (Ark UI ๊ธฐ๋ฐ˜)

ํ•˜์ง€๋งŒ ์ตœ๊ทผ์˜ ํŠธ๋ Œ๋“œ๋Š” ํ—ค๋“œ๋ฆฌ์Šค UI ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ๋ฅผ ์„ ํ˜ธํ•˜๋Š” ์ถ”์„ธ์ž…๋‹ˆ๋‹ค. ํ—ค๋“œ๋ฆฌ์Šค ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ๋Š” ์Šคํƒ€์ผ๋ง ์—†์ด ์ œ๊ณต๋˜์ง€๋งŒ, ์ตœ์‹  ์ปดํฌ๋„ŒํŠธ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ์— ํ•„์š”ํ•œ ๋ชจ๋“  ๊ธฐ๋Šฅ๊ณผ ์ ‘๊ทผ์„ฑ์„ ๊ฐ–์ถ”๊ณ  ์žˆ์Šต๋‹ˆ๋‹ค. ๋Œ€๋ถ€๋ถ„ Tailwind์™€ ๊ฐ™์€ ์œ ํ‹ธ๋ฆฌํ‹ฐ ์šฐ์„  CSS ์†”๋ฃจ์…˜๊ณผ ํ•จ๊ป˜ ์‚ฌ์šฉ๋ฉ๋‹ˆ๋‹ค.

๋‹ค๋ฅธ UI ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ๊ณผ ๋น„๊ตํ–ˆ์„ ๋•Œ, ์ธ๊ธฐ๊ฐ€ ๋œ ํ•œ ๊ฒƒ์œผ๋กœ ๋ณด์ž…๋‹ˆ๋‹ค.

์ด๋Ÿฌํ•œ ๋ชจ๋“  UI ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ์—๋Š” ์ž์ฒด ์ปดํฌ๋„ŒํŠธ๊ฐ€ ํฌํ•จ๋˜์–ด ์žˆ์ง€๋งŒ, ๊ฐ ์ปดํฌ๋„ŒํŠธ๋ฅผ ํ•˜๋‚˜์˜ UI ์ปดํฌ๋„ŒํŠธ์— ์ค‘์ ์„ ๋‘” ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ๋งŒํผ ๊ฐ•๋ ฅํ•˜๊ฒŒ ๋งŒ๋“ค ์ˆ˜๋Š” ์—†์Šต๋‹ˆ๋‹ค. ์˜ˆ๋ฅผ ๋“ค์–ด, react-table-library๋ฅผ ์‚ฌ์šฉํ•˜๋ฉด ๋ฆฌ์•กํŠธ์—์„œ ๊ฐ•๋ ฅํ•œ ํ…Œ์ด๋ธ” ์ปดํฌ๋„ŒํŠธ๋ฅผ ๋งŒ๋“ค ์ˆ˜ ์žˆ๋Š” ๋™์‹œ์—, ์ด๋ฅผ UI ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ์™€ ๊ฒฐํ•ฉํ•  ์ˆ˜ ์žˆ๋Š” ํ…Œ๋งˆ(์˜ˆ: Material UI)๋„ ์ œ๊ณตํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

๋ฆฌ์•กํŠธ ์• ๋‹ˆ๋ฉ”์ด์…˜ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ

์›น ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜์˜ ๋ชจ๋“  ์• ๋‹ˆ๋ฉ”์ด์…˜์€ CSS๋กœ ์‹œ์ž‘ํ•ฉ๋‹ˆ๋‹ค. ๊ฒฐ๊ตญ CSS ์• ๋‹ˆ๋ฉ”์ด์…˜๋งŒ์œผ๋กœ๋Š” ์š”๊ตฌ ์‚ฌํ•ญ์„ ์ถฉ์กฑ์‹œํ‚ค๊ธฐ ์–ด๋ ต๋‹ค๋Š” ๊ฒƒ์„ ์•Œ๊ฒŒ ๋  ๊ฒƒ์ž…๋‹ˆ๋‹ค. ๋ณดํ†ต ๊ฐœ๋ฐœ์ž๋“ค์€ ๊ทธ๋Ÿด ๋•Œ ๋ฆฌ์•กํŠธ ์ปดํฌ๋„ŒํŠธ๋กœ ์• ๋‹ˆ๋ฉ”์ด์…˜์„ ๊ตฌํ˜„ํ•  ์ˆ˜ ์žˆ๋Š” React Transition Group์„ ์‚ดํŽด๋ด…๋‹ˆ๋‹ค. ๋ฆฌ์•กํŠธ๋ฅผ ์œ„ํ•œ ๋‹ค๋ฅธ ์ž˜ ์•Œ๋ ค์ง„ ์• ๋‹ˆ๋ฉ”์ด์…˜ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ๋Š” ๋‹ค์Œ๊ณผ ๊ฐ™์Šต๋‹ˆ๋‹ค.

๋ฆฌ์•กํŠธ ์‹œ๊ฐํ™” & ์ฐจํŠธ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ

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

  • Recharts (๊ฐœ์ธ์ ์ธ ์ถ”์ฒœ)

    • ์ฆ‰์‹œ ์‚ฌ์šฉ ๊ฐ€๋Šฅํ•œ ์ฐจํŠธ
    • ๋›ฐ์–ด๋‚œ ๊ตฌ์„ฑ
    • ์„ ํƒ์  ๊ตฌ์„ฑ ๊ธฐ๋Šฅ์œผ๋กœ ์ธํ•œ ์ปค์Šคํ„ฐ๋งˆ์ด์ง•
  • visx

    • ๊ณ ์ˆ˜์ค€ ์ถ”์ƒํ™”๋ณด๋‹ค ๋‚ฎ์€ ์ˆ˜์ค€์˜ D3์— ๋” ๊ฐ€๊นŒ์›€
    • ๊ฐ€ํŒŒ๋ฅธ ํ•™์Šต ๊ณก์„ 
  • ์ฆ‰์‹œ ์‚ฌ์šฉ ๊ฐ€๋Šฅํ•œ ์ฐจํŠธ๊ฐ€ ๋” ๋งŽ์ง€๋งŒ, ์ปค์Šคํ„ฐ๋งˆ์ด์ง•์ด ๋” ์–ด๋ ค์›€

๋ฆฌ์•กํŠธ ํผ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ

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

๊ณ„์† ์ฝ๊ธฐ : ๋ฆฌ์•กํŠธ์—์„œ ํผ์„ ์‚ฌ์šฉํ•˜๋Š” ๋ฐฉ๋ฒ•

์ถ”์ฒœ

  • React Hook Form

    • ์œ ํšจ์„ฑ ๊ฒ€์‚ฌ๋ฅผ ์œ„ํ•œ zod ํ†ตํ•ฉ

๋ฆฌ์•กํŠธ ํƒ€์ž… ๊ฒ€์‚ฌ

๋ฆฌ์•กํŠธ๋Š” PropTypes๋ผ๋Š” ๋‚ด๋ถ€ ํ”„๋กญ ์œ ํšจ์„ฑ ๊ฒ€์‚ฌ ๊ธฐ๋Šฅ์„ ์ œ๊ณตํ•ฉ๋‹ˆ๋‹ค. PropTypes๋ฅผ ์‚ฌ์šฉํ•˜๋ฉด ๋ฆฌ์•กํŠธ ์ปดํฌ๋„ŒํŠธ์— ๋Œ€ํ•œ ํ”„๋กญ๋ฅผ ์ •์˜ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ์ž˜๋ชป๋œ ํƒ€์ž…์˜ ํ”„๋กญ์ด ์ปดํฌ๋„ŒํŠธ์— ์ „๋‹ฌ๋  ๋•Œ๋งˆ๋‹ค ์˜ค๋ฅ˜ ๋ฉ”์‹œ์ง€๊ฐ€ ํ‘œ์‹œ๋ฉ๋‹ˆ๋‹ค.

import PropTypes from 'prop-types';

const List = ({ list }) => (
  <div>
    {list.map(item => (
      <div key={item.id}>{item.title}</div>
    ))}
  </div>
);

List.propTypes = {
  list: PropTypes.array.isRequired,
};

๊ทธ๋Ÿฌ๋‚˜ PropTypes๋Š” ๋” ์ด์ƒ ๋ฆฌ์•กํŠธ์— ํฌํ•จ๋˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค. ์ €๋Š” ์‚ฌ์šฉ์„ ์ถ”์ฒœํ•˜์ง€ ์•Š์ง€๋งŒ, ์—ญ์‚ฌ์ ์ธ ์ด์œ ๋กœ ์—ฌ์ „ํžˆ ์—ฌ๊ธฐ์— ๋‚จ๊ฒจ๋‘๊ณ  ์žˆ์Šต๋‹ˆ๋‹ค.

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

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

type ListProps = {
  list: Item[];
};

const List = ({ list }: ListProps) => (
  <div>
    {list.map(item => (
      <div key={item.id}>{item.title}</div>
    ))}
  </div>
);

์š”์ฆ˜์€ ํƒ€์ž…์Šคํฌ๋ฆฝํŠธ๊ฐ€ ๋Œ€์„ธ์ž…๋‹ˆ๋‹ค. ํƒ€์ž…์ด ์ง€์ •๋œ ์–‘์‹ ์œ ํšจ์„ฑ ๊ฒ€์‚ฌ, API ์œ ํšจ์„ฑ ๊ฒ€์‚ฌ(์˜ˆ: tRPC ์‚ฌ์šฉ ์‹œ)๋“ฑ์„ ์œ„ํ•ด ํƒ€์ž…์Šคํฌ๋ฆฝํŠธ๋ฅผ ๋„˜์–ด์„œ๊ณ  ์‹ถ๋‹ค๋ฉด Zod๋ฅผ ํ™•์ธํ•ด ๋ณด์„ธ์š”.

์ถ”์ฒœ

  • ํƒ€์ž…์ด ์ง€์ •๋œ ์ž๋ฐ”์Šคํฌ๋ฆฝํŠธ๊ฐ€ ํ•„์š”ํ•œ ๊ฒฝ์šฐ, ํƒ€์ž…์Šคํฌ๋ฆฝํŠธ๋ฅผ ์‚ฌ์šฉํ•ฉ๋‹ˆ๋‹ค.

๋ฆฌ์•กํŠธ ์ฝ”๋“œ ๊ตฌ์กฐ

ํ†ต์ผ๋˜๊ณ  ์ผ๋ฐ˜์ ์ธ ์ฝ”๋“œ ์Šคํƒ€์ผ์„ ์œ ์ง€ํ•˜๊ณ  ์‹ถ๋‹ค๋ฉด ๋ฆฌ์•กํŠธ ํ”„๋กœ์ ํŠธ์—์„œ ESLint๋ฅผ ์‚ฌ์šฉํ•˜์„ธ์š”. ESLint์™€ ๊ฐ™์€ ๋ฆฐํ„ฐ๋Š” ํŠน์ • ์ฝ”๋“œ ์Šคํƒ€์ผ์„ ๊ฐ•์ œํ•ฉ๋‹ˆ๋‹ค. ์˜ˆ๋ฅผ ๋“ค์–ด, ์ธ๊ธฐ ์žˆ๋Š” ์Šคํƒ€์ผ ๊ฐ€์ด๋“œ(์˜ˆ: ์—์–ด๋น„์•ค๋น„ ์Šคํƒ€์ผ ๊ฐ€์ด๋“œ)๋ฅผ ๋”ฐ๋ฅด๋„๋ก ESLint์—์„œ ์š”๊ตฌ์‚ฌํ•ญ์œผ๋กœ ์„ค์ •ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ๋˜ํ•œ IDE/ํŽธ์ง‘๊ธฐ์— ESLint๋ฅผ ํ†ตํ•ฉํ•˜๋ฉด ๋ชจ๋“  ์‹ค์ˆ˜๋ฅผ ํ‘œ์‹œํ•ด ์ค๋‹ˆ๋‹ค.

๊ณ„์† ์ฝ๊ธฐ : ๋ฆฌ์•กํŠธ ํŒŒ์ผ/ํด๋” ๊ตฌ์กฐ(์ข…ํ•ฉ ํŠœํ† ๋ฆฌ์–ผ)

ํ†ตํ•ฉ๋œ ์ฝ”๋“œ ํ˜•์‹์„ ์‚ฌ์šฉํ•˜๋ ค๋ฉด ๋ฆฌ์•กํŠธ ํ”„๋กœ์ ํŠธ์—์„œ Prettier๋ฅผ ์‚ฌ์šฉํ•˜์„ธ์š”. ๋ช‡ ๊ฐ€์ง€ ์˜ต์…˜๋งŒ ์„ค์ •ํ•  ์ˆ˜ ์žˆ๋Š” ๋…๋‹จ์ ์ธ ์ฝ”๋“œ ํฌ๋งทํ„ฐ์ž…๋‹ˆ๋‹ค. ํŒŒ์ผ์„ ์ €์žฅํ•  ๋•Œ๋งˆ๋‹ค ์ฝ”๋“œ ํฌ๋งท์„ ์ง€์ •ํ•˜๋„๋ก ํŽธ์ง‘๊ธฐ๋‚˜ IDE์— ํ†ตํ•ฉํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. Prettier๋Š” ESLint๋ฅผ ๋Œ€์ฒดํ•˜์ง€๋Š” ์•Š์ง€๋งŒ, ESLint์™€ ์ž˜ ํ†ตํ•ฉ๋ฉ๋‹ˆ๋‹ค.

2024๋…„์— ๋– ์˜ค๋ฅด๋Š” ์Šคํƒ€๋Š” ์•„๋งˆ๋„ Biome(์ด์ „์˜ Rome)์ด ๋  ๊ฒƒ์ž…๋‹ˆ๋‹ค. ESLint์™€ Prettier๋Š” ์„ค์ •์ด๋‚˜ ํŠนํžˆ ์ƒํ˜ธ ์ž‘์šฉ ์ธก๋ฉด์—์„œ ๊ฐ€์žฅ ์„ ํ˜ธ๋˜๋Š” ๋„๊ตฌ๋Š” ์•„๋‹™๋‹ˆ๋‹ค. ํ•˜์ง€๋งŒ ๋ชจ๋“  ์›น ๊ฐœ๋ฐœ์ž์˜ ์ผ์ƒ ์—…๋ฌด์— ๋ฐ˜๋“œ์‹œ ํ•„์š”ํ•ฉ๋‹ˆ๋‹ค. Biome์€ ๋น ๋ฅธ(Rust ๊ธฐ๋ฐ˜) ์˜ฌ์ธ์› ํˆด์ฒด์ธ์„ ์ œ๊ณตํ•จ์œผ๋กœ์จ Prettier์™€ ESLint์˜ ๋Œ€์•ˆ์ด ๋˜๊ณ ์ž ํ•ฉ๋‹ˆ๋‹ค.

์ถ”์ฒœ

  • ESLint + Prettier
  • Biome๋„ ์‚ฌ์šฉํ•ด ๋ณด์„ธ์š”.

๋ฆฌ์•กํŠธ ์ธ์ฆ

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

๊ณ„์† ์ฝ๊ธฐ : React Router๋กœ ์ธ์ฆ์„ ์ค€๋น„ํ•˜๋Š” ๋ฐฉ๋ฒ•

๊ฐ€์žฅ ์ข‹์€ ํ•™์Šต ๊ฒฝํ—˜์€ ์ธ์ฆ ๊ธฐ๋Šฅ์ด ์žˆ๋Š” ๋ฐฑ์—”๋“œ ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜(์˜ˆ: GraphQL ๋ฐฑ์—”๋“œ)์„ ์ง์ ‘ ๊ตฌํ˜„ํ•˜๋Š” ๊ฒƒ์ž…๋‹ˆ๋‹ค. ๊ทธ๋Ÿฌ๋‚˜ ์ธ์ฆ์—๋Š” ๋งŽ์€ ๋ณด์•ˆ ์œ„ํ—˜๊ณผ ๋งŽ์€ ์‚ฌ๋žŒ์ด ์•Œ์ง€ ๋ชปํ•˜๋Š” ์„ธ๋ถ€ ์‚ฌํ•ญ์ด ์ˆ˜๋ฐ˜๋˜๋ฏ€๋กœ, ์‹œ์ค‘์— ๋‚˜์™€ ์žˆ๋Š” ๋งŽ์€ ์ธ์ฆ/๋ฐฑ์—”๋“œ ์„œ๋น„์Šค ์†”๋ฃจ์…˜ ์ค‘ ํ•˜๋‚˜๋ฅผ ์‚ฌ์šฉํ•˜๋Š”๊ฒƒ์ด ์ข‹์Šต๋‹ˆ๋‹ค.

  • Lucia

    • ๋งค์šฐ ํฅ๋ฏธ๋กœ์šด ์˜คํ”ˆ์†Œ์Šค ํ”„๋กœ์ ํŠธ
    • ์–ด๋– ํ•œ ์„œ๋“œํŒŒํ‹ฐ ์„œ๋น„์Šค์—๋„ ๋…๋ฆฝ์ ์ด๊ฒŒ ๋งŒ๋“ค์–ด์ค๋‹ˆ๋‹ค.
  • Supabase Auth
  • Clerk
  • AuthKit
  • NextAuth
  • Firebase Auth
  • Auth0
  • AWS Cognito

๋ฆฌ์•กํŠธ ๋ฐฑ์—”๋“œ

๋ฆฌ์•กํŠธ๋ฅผ ์„œ๋ฒ„๋กœ ์ด๋™์‹œํ‚ค๋Š” ๊ฐ•๋ ฅํ•œ ์ถ”์„ธ๊ฐ€ ์žˆ๊ธฐ ๋•Œ๋ฌธ์— ๋ฆฌ์•กํŠธ ํ”„๋กœ์ ํŠธ์˜ ๊ฐ€์žฅ ์ž์—ฐ์Šค๋Ÿฌ์šด ํ™˜๊ฒฝ์€ Next.js, Astro ๋˜๋Š” Remix์™€ ๊ฐ™์€ ๋ฉ”ํƒ€ ํ”„๋ ˆ์ž„์›Œํฌ์ผ ๊ฒƒ์ž…๋‹ˆ๋‹ค.

๋งŒ์•ฝ ๋‹ค์–‘ํ•œ ์ด์œ ๋กœ JS/TS๋Š” ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ์ง€๋งŒ ํ’€์Šคํƒ ํ”„๋ ˆ์ž„์›Œํฌ๋ฅผ ์‚ฌ์šฉํ•  ์ˆ˜ ์—†๋‹ค๋ฉด, tRPC ๋˜๋Š” Hono๋ฅผ ํ™•์ธํ•ด ๋ณด์…”์•ผ ํ•ฉ๋‹ˆ๋‹ค. ๊ตฌ์‹์ด์ง€๋งŒ ์—ฌ์ „ํžˆ ์ธ๊ธฐ ์žˆ๋Š” Express๋ฅผ ๊ธฐ๋ฐ˜์œผ๋กœ ํ•˜๋Š” Node ๋ฐฑ์—”๋“œ๋„ ์–ธ๊ธ‰ํ•  ๋งŒํ•ฉ๋‹ˆ๋‹ค. ๋‹ค๋ฅธ ๋Œ€์•ˆ์œผ๋กœ๋Š” Fastify๋‚˜ Nest๊ฐ€ ์žˆ์Šต๋‹ˆ๋‹ค.

๋ฆฌ์•กํŠธ ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค

๋ฆฌ์•กํŠธ์™€ ์ง์ ‘์ ์œผ๋กœ ๊ด€๋ จ์ด ์žˆ๋Š” ๊ฒƒ์€ ์•„๋‹ˆ์ง€๋งŒ, ์š”์ฆ˜ ํ’€์Šคํƒ ๋ฆฌ์•กํŠธ ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜์ด ์ธ๊ธฐ๋ฅผ ์–ป๊ณ  ์žˆ๊ธฐ ๋•Œ๋ฌธ์— ๋ฆฌ์•กํŠธ๋Š” ๊ทธ ์–ด๋А ๋•Œ๋ณด๋‹ค ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค ๊ณ„์ธต๊ณผ ๊ฐ€๊นŒ์›Œ์กŒ์Šต๋‹ˆ๋‹ค. Next.js ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜์„ ๊ฐœ๋ฐœํ•˜๋Š” ๋™์•ˆ, ๋Œ€๋ถ€๋ถ„ ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค ORM์„ ๋‹ค๋ฃจ๊ฒŒ ๋  ๊ฐ€๋Šฅ์„ฑ์ด ๋†’์Šต๋‹ˆ๋‹ค. ์š”์ฆ˜ ๊ฐ€์žฅ ์ธ๊ธฐ ์žˆ๋Š” ORM์€ Prisma์ž…๋‹ˆ๋‹ค. ์ตœ๊ทผ ์œ ํ–‰ํ•˜๋Š” ๋Œ€์•ˆ์€ Drizzle ORM์ž…๋‹ˆ๋‹ค. ๋” ๋งŽ์€ ๋Œ€์•ˆ์œผ๋กœ๋Š” Kysely์™€ database-js(PlanetScale์—๋งŒ ํ•ด๋‹น)๊ฐ€ ์žˆ์Šต๋‹ˆ๋‹ค.

๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค ์„ ํƒ์— ์žˆ์–ด์„œ๋Š” Supabase(๋˜๋Š” Firebase)๊ฐ€ ์œ ํšจํ•œ ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค ์ œ๊ณต์—…์ฒด์ž…๋‹ˆ๋‹ค. PostgreSQL์„ ์‚ฌ์šฉํ•˜๋Š” Supabase๋Š” ์ž์ฒด ํ˜ธ์ŠคํŒ…ํ•˜๊ฑฐ๋‚˜ ์œ ๋ฃŒ ์„œ๋น„์Šค๋กœ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ์„œ๋ฒ„๋ฆฌ์Šค ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค๋ฅผ ์ œ๊ณตํ•˜๋Š” ์ธ๊ธฐ ์žˆ๋Š” ๋Œ€์•ˆ์œผ๋กœ๋Š” PlanetScale(๊ฐœ์ธ์  ์ถ”์ฒœ), Neon, Xata๊ฐ€ ์žˆ์Šต๋‹ˆ๋‹ค.

๊ณ„์† ์ฝ๊ธฐ : ์›น ๊ฐœ๋ฐœ ํŠธ๋ Œ๋“œ

๋ฆฌ์•กํŠธ ํ˜ธ์ŠคํŒ…

๋ฆฌ์•กํŠธ ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜์„ ๋‹ค๋ฅธ ์›น ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜์ฒ˜๋Ÿผ ๋ฐฐํฌํ•˜๊ณ  ํ˜ธ์ŠคํŒ…ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ์™„์ „ํ•œ ์ œ์–ด๋ฅผ ์›ํ•œ๋‹ค๋ฉด Digital Ocean๊ณผ ๊ฐ™์€ ๊ฒƒ์„ ์„ ํƒํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ๋ˆ„๊ตฐ๊ฐ€ ๋Œ€์‹  ๋ชจ๋“  ๊ฒƒ์„ ์ฒ˜๋ฆฌํ•ด์ฃผ๊ธธ ์›ํ•œ๋‹ค๋ฉด Netlify๋‚˜ Vercel (ํŠนํžˆ Next.js์˜ ๊ฒฝ์šฐ)์ด ์ธ๊ธฐ ์žˆ๋Š” ์†”๋ฃจ์…˜์ž…๋‹ˆ๋‹ค.

์ด๋ฏธ Firebase/Supabase์™€ ๊ฐ™์€ ์„œ๋“œํŒŒํ‹ฐ ๋ฐฑ์—”๋“œ ์„œ๋น„์Šค๋ฅผ ์‚ฌ์šฉํ•˜๊ณ  ์žˆ๋‹ค๋ฉด, ํ•ด๋‹น ์„œ๋น„์Šค๊ฐ€ ํ˜ธ์ŠคํŒ…๋„ ์ œ๊ณตํ•˜๋Š”์ง€ ํ™•์ธํ•ด ๋ณผ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ๋‹ค๋ฅธ ์ธ๊ธฐ ์žˆ๋Š” ํ˜ธ์ŠคํŒ… ์ œ๊ณต์ž๋กœ๋Š” Render, Fly.io, Railway, ๋˜๋Š” ๋” ์ง์ ‘์ ์ธ AWS/Azure/Google Cloud/Hetzner ๋“ฑ์ด ์žˆ์Šต๋‹ˆ๋‹ค.

๋ฆฌ์•กํŠธ ํ…Œ์ŠคํŒ…

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

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

๊ฒฐ๊ตญ์—๋Š” React Testing Library (RTL)๋ฅผ ์‚ฌ์šฉํ•˜๊ฒŒ ๋  ๊ฒƒ์ž…๋‹ˆ๋‹ค. ์ด๋Š” ํ…Œ์ŠคํŠธ ํ”„๋ ˆ์ž„์›Œํฌ ํ™˜๊ฒฝ ๋‚ด์—์„œ ๋„๋ฆฌ ์‚ฌ์šฉ๋˜๋ฉฐ, ๋ฆฌ์•กํŠธ๋ฅผ ์œ„ํ•œ ํฌ๊ด„์ ์ธ ํ…Œ์ŠคํŒ… ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ์ž…๋‹ˆ๋‹ค. RTL์„ ์‚ฌ์šฉํ•˜๋ฉด ์ปดํฌ๋„ŒํŠธ๋ฅผ ๋ Œ๋”๋งํ•˜๊ณ  HTML ์š”์†Œ์—์„œ ์ด๋ฒคํŠธ๋ฅผ ์‹œ๋ฎฌ๋ ˆ์ด์…˜ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ๊ทธ ํ›„์—๋Š” ์–ด์„ค์…˜์„ ์œ„ํ•ด ํ…Œ์ŠคํŠธ ํ”„๋ ˆ์ž„์›Œํฌ๊ฐ€ ์‚ฌ์šฉ๋ฉ๋‹ˆ๋‹ค.

๋ฆฌ์•กํŠธ E2E ํ…Œ์ŠคํŠธ๋ฅผ ์œ„ํ•œ ๋„๊ตฌ๋ฅผ ์ฐพ๊ณ  ์žˆ๋‹ค๋ฉด, Playwright์™€ Cypress๊ฐ€ ๊ฐ€์žฅ ์ธ๊ธฐ ์žˆ๋Š” ์„ ํƒ์ง€์ž…๋‹ˆ๋‹ค.

์ถ”์ฒœ

  • ๋‹จ์œ„/ํ†ตํ•ฉ: Vitest + React Testing Library(๊ฐ€์žฅ ์ธ๊ธฐ ์žˆ์Œ)
  • ์Šค๋ƒ…์ƒท ํ…Œ์ŠคํŠธ: Vitest
  • E2E ํ…Œ์ŠคํŠธ: Playwright ๋˜๋Š” Cypress

๋ฆฌ์•กํŠธ ๋ถˆ๋ณ€ ๋ฐ์ดํ„ฐ ๊ตฌ์กฐ

๋ฐ”๋‹๋ผ ์ž๋ฐ”์Šคํฌ๋ฆฝํŠธ๋Š” ๋ฐ์ดํ„ฐ ๊ตฌ์กฐ๋ฅผ ๋ถˆ๋ณ€์ธ ๊ฒƒ์ฒ˜๋Ÿผ ์ฒ˜๋ฆฌํ•  ์ˆ˜ ์žˆ๋Š” ๋‹ค์–‘ํ•œ ๋‚ด์žฅ ๋„๊ตฌ๋ฅผ ์ œ๊ณตํ•ฉ๋‹ˆ๋‹ค. ํ•˜์ง€๋งŒ ๋ถˆ๋ณ€์˜ ๋ฐ์ดํ„ฐ ๊ตฌ์กฐ๋ฅผ ๊ฐ•์ œํ•ด์•ผ ํ•  ํ•„์š”์„ฑ์„ ๋А๋‚€๋‹ค๋ฉด, ๊ฐ€์žฅ ๋งŽ์ด ์‚ฌ์šฉ๋˜๋Š” ๋„๊ตฌ๋Š” Immer์ž…๋‹ˆ๋‹ค.

๋ฆฌ์•กํŠธ ๊ตญ์ œํ™”

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

๋ฆฌ์•กํŠธ ๋ฆฌ์น˜ ํ…์ŠคํŠธ ํŽธ์ง‘๊ธฐ

๋ฆฌ์•กํŠธ์˜ ๋ฆฌ์น˜ ํ…์ŠคํŠธ ํŽธ์ง‘๊ธฐ์— ๊ด€ํ•ด์„œ๋Š” ์•„๋ž˜ ํ›„๋ณด๋งŒ ๋– ์˜ฌ๋ฆด ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

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

๊ฐ€์žฅ ์ผ๋ฐ˜์ ์ธ ๊ฒฐ์ œ ๊ณต๊ธ‰์ž๋Š” Stripe์™€ PayPal์ž…๋‹ˆ๋‹ค. ๋‘˜ ๋‹ค ๋ฆฌ์•กํŠธ์— ์†์‰ฝ๊ฒŒ ํ†ตํ•ฉ๋  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ๋‹ค์Œ์€ ์ž‘๋™ํ•˜๋Š” Stripe Checkout๊ณผ ๋ฆฌ์•กํŠธ ํ†ตํ•ฉ ์˜ˆ์ œ์ž…๋‹ˆ๋‹ค.

๋ฆฌ์•กํŠธ ์‹œ๊ฐ„

๋ฆฌ์•กํŠธ ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜์ด ๋‚ ์งœ, ์‹œ๊ฐ„ ๋ฐ ์‹œ๊ฐ„๋Œ€๋ฅผ ๋งŽ์ด ๋‹ค๋ฃจ๋Š” ๊ฒฝ์šฐ, ์ด๋Ÿฌํ•œ ์š”์†Œ๋“ค์„ ๊ด€๋ฆฌํ•ด ์ฃผ๋Š” ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ๋ฅผ ๋„์ž…ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ์—ฌ๊ธฐ ๋ช‡ ๊ฐ€์ง€ ์˜ต์…˜๋“ค์ž…๋‹ˆ๋‹ค.

๋ฆฌ์•กํŠธ ๋ฐ์Šคํฌํ†ฑ ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜

Electron๊ณผ Tauri๋Š” ํฌ๋กœ์Šค ํ”Œ๋žซํผ ๋ฐ์Šคํฌํ†ฑ ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜์„ ๊ฐœ๋ฐœํ•˜๊ธฐ ์œ„ํ•œ ์ฃผ์š” ํ”„๋ ˆ์ž„์›Œํฌ์ž…๋‹ˆ๋‹ค.

๋ฆฌ์•กํŠธ ํŒŒ์ผ ์—…๋กœ๋“œ

๋ฆฌ์•กํŠธ ๋ฉ”์ผ

๋“œ๋ž˜๊ทธ ์•ค ๋“œ๋กญ

๊ฐœ์ธ์ ์œผ๋กœ react-beautiful-dnd์˜ ํ›„์† ๋ฒ„์ „์„ ์‚ฌ์šฉํ•ด ๋ดค๋Š”๋ฐ, ์ •๋ง ์ข‹์•˜์Šต๋‹ˆ๋‹ค. ํ›จ์”ฌ ๋งŽ์€ ์œ ์—ฐ์„ฑ๊ณผ ์˜ต์…˜์„ ์ œ๊ณตํ•˜์ง€๋งŒ ํ•™์Šต ๊ณก์„ ์ด ๋‹ค์†Œ ๊ฐ€ํŒŒ๋ฅธ ๋น„์šฉ์ด ์žˆ๋Š” ์ธ๊ธฐ ์žˆ๋Š” ๋Œ€์•ˆ์œผ๋กœ๋Š” dnd kit์ด ์žˆ์Šต๋‹ˆ๋‹ค. ์ด ๋ถ„์•ผ์˜ ๋˜ ๋‹ค๋ฅธ ๋Œ€์•ˆ์œผ๋กœ๋Š” react-dnd๊ฐ€ ์žˆ์Šต๋‹ˆ๋‹ค.

๋ฆฌ์•กํŠธ ๋ชจ๋ฐ”์ผ ๊ฐœ๋ฐœ

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

๊ณ„์† ์ฝ๊ธฐ : React Native์—์„œ ํƒ์ƒ‰ ๋ฐฐ์šฐ๊ธฐ

๋ฆฌ์•กํŠธ VR/AR

๋ฆฌ์•กํŠธ๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ๊ฐ€์ƒ ํ˜„์‹ค(VR)์ด๋‚˜ ์ฆ๊ฐ• ํ˜„์‹ค(AR)๋กœ ๋›ฐ์–ด๋“ค ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ์†”์งํžˆ ๋งํ•ด์„œ, ์ด๋Ÿฌํ•œ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ ์ค‘ ์–ด๋А ๊ฒƒ๋„ ์‚ฌ์šฉํ•œ ์ ์€ ์—†๊ณ  ๋Œ€๋ถ€๋ถ„์ด ์ดˆ๊ธฐ ๋‹จ๊ณ„(์‹คํ—˜์ )์— ์žˆ์ง€๋งŒ AR/VR์—์„œ ๋ฆฌ์•กํŠธ๋ฅผ ๋‹ค๋ฃฐ ๋•Œ ์ œ๊ฐ€ ์•Œ๊ณ  ์žˆ๋Š” ๋ช‡ ๊ฐ€์ง€ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ๋Š” ๋‹ค์Œ๊ณผ ๊ฐ™์Šต๋‹ˆ๋‹ค.

  • react-three-fiber (์ธ๊ธฐ ์žˆ๋Š” 3D ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ์ด์ง€๋งŒ, VR ์‚ฌ๋ก€๋„ ๋ณด์•˜์Šต๋‹ˆ๋‹ค.)
  • react-360
  • aframe-react

๋ฆฌ์•กํŠธ ๋””์ž์ธ ํ”„๋กœํ† ํƒ€์ดํ•‘

UI/UX ๋ฐฐ๊ฒฝ์„ ๊ฐ€์ง€๊ณ  ์žˆ๋‹ค๋ฉด, ์ƒˆ๋กœ์šด ๋ฆฌ์•กํŠธ ์ปดํฌ๋„ŒํŠธ, ๋ ˆ์ด์•„์›ƒ ๋˜๋Š” UI/UX ๊ฐœ๋…์„ ๋น ๋ฅด๊ฒŒ ํ”„๋กœํ† ํƒ€์ดํ•‘ํ•  ์ˆ˜ ์žˆ๋Š” ๋„๊ตฌ๋ฅผ ์‚ฌ์šฉํ•˜๊ณ  ์‹ถ์„ ๊ฒƒ์ž…๋‹ˆ๋‹ค. ๊ฐœ์ธ์ ์œผ๋กœ๋Š” Figma๋ฅผ ์‚ฌ์šฉํ•ฉ๋‹ˆ๋‹ค. ๋Œ€๋žต์ ์ด๊ณ  ๊ฐ€๋ฒผ์šด ์Šค์ผ€์น˜์—๋Š” Excalidraw๋ฅผ ์„ ํ˜ธํ•˜๋ฉฐ, ์–ด๋–ค ์‚ฌ๋žŒ๋“ค์€ tldraw๋ฅผ ์„ ํ˜ธํ•˜๊ธฐ๋„ ํ•ฉ๋‹ˆ๋‹ค.

๋ฆฌ์•กํŠธ ์ปดํฌ๋„ŒํŠธ ๋ฌธ์„œํ™”

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

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


๐Ÿš€ ํ•œ๊ตญ์–ด๋กœ ๋œ ํ”„๋ŸฐํŠธ์—”๋“œ ์•„ํ‹ฐํด์„ ๋น ๋ฅด๊ฒŒ ๋ฐ›์•„๋ณด๊ณ  ์‹ถ๋‹ค๋ฉด Korean FE Article(https://kofearticle.substack.com/)์„ ๊ตฌ๋…ํ•ด ์ฃผ์„ธ์š”!


[Ykss]
Written by@[Ykss]
๊ณ ์ด๊ฒŒ ๋‘์ง€ ์•Š๊ณ  ํ˜๋ ค๋ณด๋‚ด๋Š” ๊ฐœ๋ฐœ์ž๊ฐ€ ๋˜์ž.

GitHubInstagramLinkedIn