๐Ÿ“Ž React

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

Learn React - Describing the UI

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

Describing the UI ํ…์˜ ์š”์•ฝ ๋‚ด์šฉ์€ ์งง๊ฒŒ ์ž‘์„ฑํ•˜๊ณ  ๋„˜์–ด๊ฐ€๊ฒ ์Šต๋‹ˆ๋‹ค.

  1. ๋‹น์‹ ์˜ ์ฒซ ์ปดํฌ๋„ŒํŠธ

๋ฆฌ์•กํŠธ ์–ดํ”Œ๋ฆฌ์ผ€์ด์…˜์€ ์ปดํฌ๋„ŒํŠธ๋ผ๊ณ  ๋ถˆ๋ฆฌ๋Š” ๋…๋ฆฝ๋œ UI ์กฐ๊ฐ๋“ค๋กœ ๊ตฌ์„ฑ๋œ๋‹ค. ๋ฆฌ์•กํŠธ ์ปดํฌ๋„ŒํŠธ๋Š” ๋งˆํฌ์—…์„ ๋ฟŒ๋ฆฌ๋Š” ์ž๋ฐ”์Šคํฌ๋ฆฝํŠธ ํ•จ์ˆ˜์ด๋‹ค. ์ปดํฌ๋„ŒํŠธ๋“ค์€ ๋ฒ„ํŠผ์ฒ˜๋Ÿผ ์ž‘์„ ์ˆ˜๋„, ์ „์ฒด ํŽ˜์ด์ง€์ฒ˜๋Ÿผ ํด ์ˆ˜๋„ ์žˆ๋‹ค.

  1. ์ปดํฌ๋„ŒํŠธ๋ฅผ ๋ถˆ๋Ÿฌ์˜ค๊ณ  ๋‚ด๋ณด๋‚ด๊ธฐ(Importing and Exporting Components)

๋‹น์‹ ์€ ํ•˜๋‚˜์˜ ํŒŒ์ผ์—์„œ ๋งŽ์€ ์ปดํฌ๋„ŒํŠธ๋“ค์„ ์„ ์–ธํ•  ์ˆ˜ ์žˆ์ง€๋งŒ ๋งค์šฐ ํฐ ํŒŒ์ผ์€ ์œ ์ง€๋ณด์ˆ˜ํ•˜๊ธฐ ํž˜๋“ค๋‹ค. ์ด๋Ÿฐ ๋ฌธ์ œ๋ฅผ ํ•ด๊ฒฐํ•˜๊ธฐ ์œ„ํ•ด esm(import, export)๋ฅผ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๋‹ค.

์ด๊ฑด ecmascript์˜ ๊ทœ๊ฒฉ์ธ๋ฐ, ์ด๊ฒŒ react์˜ ์žฅ์ ์ธ ๊ฒƒ์ฒ˜๋Ÿผ ์“ด ๊ฒŒ ๋งž๋‚˜ ์‹ถ๊ธดํ•˜๋‹ค.(๊ฒฐ๊ตญ์—” ๋ฆฌ์•กํŠธ ์ปดํฌ๋„ŒํŠธ๋„ ๊ทธ๋ƒฅ JS ํ•จ์ˆ˜์ด๊ณ  ์ด ํ•จ์ˆ˜๋ฅผ esm์œผ๋กœ ๊ด€๋ฆฌํ•˜๋Š” ๊ฒƒ ๋ฟ์ธ๋ฐ..!)

  1. JSX๋ฅผ ํ†ตํ•ด markup์„ ์ž‘์„ฑ ๊ฐ€๋Šฅ

๊ฐ ๋ฆฌ์•กํŠธ ์ปดํฌ๋„ŒํŠธ๋Š” ๋ฆฌ์•กํŠธ๊ฐ€ ๋ธŒ๋ผ์šฐ์ €๋กœ ๋ Œ๋”๋งํ•˜๋Š” ๋งˆํฌ์—…๋“ค์„ ํฌํ•จํ•˜๊ณ  ์žˆ๋Š” JS ํ•จ์ˆ˜์ด๋‹ค. ๋ฆฌ์•กํŠธ ์ปดํฌ๋„ŒํŠธ๋“ค์€ JSX๋ผ๊ณ  ๋ถˆ๋ฆฌ๋Š” syntax extension์„ ์‚ฌ์šฉํ•˜์—ฌ markup์„ ํ‘œํ˜„ํ•œ๋‹ค. JSX๋Š” HTML์ด๋ž‘ ๋น„์Šทํ•˜์ง€๋งŒ, ์ข€๋” ์—„๊ฒฉํ•˜๊ณ  ๋™์ ์ธ ์ •๋ณด๋ฅผ ๋ณด์—ฌ์ค„ ์ˆ˜ ์žˆ๋‹ค.

  1. {}(์ค‘๊ด„ํ˜ธ)๋ฅผ ํ†ตํ•ด JSX์— JS ๋ฌธ๋ฒ• ์‚ฌ์šฉํ•˜๊ธฐ

JSX๋Š” ์ž๋ฐ”์Šคํฌ๋ฆฝํŠธ ํŒŒ์ผ ์•ˆ์—์„œ (HTML ๊ฐ™์€) markup์„ ์ž‘์„ฑํ•  ์ˆ˜ ์žˆ๊ฒŒ ํ•œ๋‹ค. ๊ทธ๋ฆฌ๊ณ  ์ด๊ฒƒ์€ ๊ฐ™์€ ๊ณณ์—์„œ ๋ Œ๋”๋ง ๋กœ์ง๊ณผ ์ปจํ…์ธ ๋ฅผ ์œ ์ง€ํ•˜๊ฒŒ ํ•ด์ค€๋‹ค. ๋•Œ๋กœ๋Š” ๋‹น์‹ ์€ markup์— ์ž‘์€ JS ๋กœ์ง ํ˜น์€ ๋™์ ์ธ ๊ฐ’์„ ๋„ฃ๊ณ  ์‹ถ์„ ์ˆ˜ ์žˆ๋‹ค. ์ด๋Ÿด ๋•Œ, ๋‹น์‹ ์€ ์ค‘๊ด„ํ˜ธ๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ JSX์— JS ๋ฌธ๋ฒ•์„ ๋„ฃ์„ ์ˆ˜ ์žˆ๋‹ค.

  1. ์ปดํฌ๋„ŒํŠธ๋ฅผ ํ†ต๊ณผํ•˜๋Š” props

๋ฆฌ์•กํŠธ ์ปดํฌ๋„ŒํŠธ๋“ค์€ ์„œ๋กœ ์†Œํ†ตํ•˜๊ธฐ ์œ„ํ•ด props๋ฅผ ์‚ฌ์šฉํ•œ๋‹ค. ๋ชจ๋“  ๋ถ€๋ชจ ์ปดํฌ๋„ŒํŠธ๋Š” ๊ทธ๋“ค์˜ props๋ฅผ ์ž์‹ ์ปดํฌ๋„ŒํŠธ์—๊ฒŒ ์ „๋‹ฌํ•จ์œผ๋กœ์จ ๋ช‡๋ช‡ ์ •๋ณด๋ฅผ ์ค„ ์ˆ˜ ์žˆ๋‹ค. props๋Š” HTML attributes๋ฅผ ์ƒ๊ฐ๋‚˜๊ฒŒ ํ•˜์ง€๋งŒ, props๋ฅผ ํ†ตํ•ด์„œ๋Š” object, array, function, ์‹ฌ์ง€์–ด JSX๊นŒ์ง€๋„ ์ „๋‹ฌ ํ•  ์ˆ˜ ์žˆ๋‹ค.

  1. ์กฐ๊ฑด๋ถ€ ๋ Œ๋”๋ง

๋‹น์‹ ์˜ ์ปดํฌ๋„ŒํŠธ๋Š” ์ข…์ข… ์กฐ๊ฑด์— ๋”ฐ๋ผ์„œ ๋‹ค๋ฅธ ํ™”๋ฉด์„ ๋ณด์—ฌ์ฃผ๊ณ  ์‹ถ์„ ๊ฒƒ์ด๋‹ค. ๋ฆฌ์•กํŠธ์—์„ , JS์˜ if ์กฐ๊ฑด๋ฌธ์ฒ˜๋Ÿผ && ํ˜น์€ ? :์„ ์‚ฌ์šฉํ•˜์—ฌ ์กฐ๊ฑด๋ถ€ ๋ Œ๋”๋ง์„ ํ•  ์ˆ˜ ์žˆ๋‹ค.

  1. ๋ฆฌ์ŠคํŠธ ๋ Œ๋”๋ง

๋‹น์‹ ์€ ์–ด๋–ค ๋ฐ์ดํ„ฐ์˜ ๋ฌถ์Œ์œผ๋กœ๋ถ€ํ„ฐ ๋‹ค์ˆ˜์˜ ๋น„์Šทํ•œ ์ปดํฌ๋„ŒํŠธ๋“ค์„ ๋ณด์—ฌ์ฃผ๊ธธ ์›ํ•  ๊ฒƒ์ด๋‹ค. ๋‹น์‹ ์€ ๋ฆฌ์•กํŠธ์™€ ํ•จ๊ป˜ JS์˜ filter๊ณผ map์„ ์‚ฌ์šฉํ•˜์—ฌ ๋ฐ์ดํ„ฐ ๋ฐฐ์—ด์„ ์ปดํฌ๋„ŒํŠธ ๋ฐฐ์—ด๋กœ ๋ณ€ํ™˜ํ•  ์ˆ˜ ์žˆ๋‹ค. ๊ฐ๊ฐ์˜ ๋ฐฐ์—ด ์•„์ดํ…œ๋“ค์—๋Š” ํŠน์ •ํ•œ key๊ฐ€ ํ•„์š”ํ•˜๋‹ค.(์ค‘์š”) ๋ณดํ†ต์€ Database์˜ id๋ฅผ key๋กœ ์‚ฌ์šฉํ•œ๋‹ค. ๋ฆฌ์•กํŠธ๋Š” Key๋ฅผ ํ†ตํ•ด ๋ฐฐ์—ด์ด ๋ณ€ํ•˜๋”๋ผ๋„ ๋ฐฐ์—ด ๋‚ด๋ถ€์˜ ๊ฐ ์•„์ดํ…œ๋“ค์„ ์ถ”์ ํ•  ์ˆ˜ ์žˆ๊ฒŒ ๋œ๋‹ค.

  1. ์ปดํฌ๋„ŒํŠธ๋“ค์„ ์ˆœ์ˆ˜ํ•˜๊ฒŒ ๋‘์–ด๋ผ

๋ฆฌ์•กํŠธ ์ปดํฌ๋„ŒํŠธ๋“ค์€ ์ˆœ์ˆ˜ํ•œ ํ•จ์ˆ˜์ฒ˜๋Ÿผ ์ž‘๋™ํ•ด์•ผ ํ•œ๋‹ค.

  • ์ˆœ์ˆ˜ํ•œ ํ•จ์ˆ˜๋Š” ๋™์ผํ•œ ์ธ์ž๋ฅผ ๋ฐ›์œผ๋ฉด ํ•ญ์ƒ ๋™์ผํ•œ ๊ฒฐ๊ณผ๋ฅผ ๋ฐ˜ํ™˜ํ•œ๋‹ค.
  • ์ˆœ์ˆ˜ํ•œ ํ•จ์ˆ˜๋Š” ๋ถ€์ž‘์šฉ(side effect)์ด ์—†๋‹ค.

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

1. Your First Component

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

Components: UI building blocks

HTML์—์„œ ์ •ํ•ด์ง„ ํƒœ๊ทธ๋ฅผ ์ œ๊ณตํ•˜๋“ฏ, ๋ฆฌ์•กํŠธ์—์„œ๋Š” ๋‹น์‹ ๋งŒ์˜ ์ปดํฌ๋„ŒํŠธ๋ฅผ ๋งŒ๋“ค ์ˆ˜ ์žˆ๋‹ค. ๋˜ํ•œ, Chakra UI์™€ Material UI ๊ฐ™์€ ๋ฆฌ์•กํŠธ ์˜คํ”ˆ์†Œ์Šค ์ปค๋ฎค๋‹ˆํŠธ๋ฅผ ํ†ตํ•ด ์ˆ˜์ฒœ๊ฐœ์˜ ์ปดํฌ๋„ŒํŠธ๋ฅผ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๋‹ค. ์ฆ‰, ๋‹น์‹ ๋งŒ์˜ ์žฌ์‚ฌ์šฉ๊ฐ€๋Šฅํ•œ UI element๋ฅผ ๋งŒ๋“ค ์ˆ˜ ์žˆ๋‹ค๋Š” ๊ฒƒ์ด๋‹ค.

Defining a component

๋ฆฌ์•กํŠธ ์ปดํฌ๋„ŒํŠธ๋Š” ๋งˆํฌ์—…๊ณผ ํ•จ๊ป˜ ๋ฟŒ๋ฆด ์ˆ˜ ์žˆ๋Š” ์ž๋ฐ”์Šคํฌ๋ฆฝํŠธ ํ•จ์ˆ˜์ด๋‹ค.

Using a component

๋‹น์‹ ์ด ๋งŒ๋“  ์ปดํฌ๋„ŒํŠธ๋ฅผ ๋‹ค๋ฅธ ์ปดํฌ๋„ŒํŠธ์˜ ๋‚ด๋ถ€์—์„œ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๋‹ค.(์ด๊ฑธ composition ํ˜น์€ nesting์ด๋ผ๊ณ  ํ•œ๋‹ค.) ์ด๊ฒƒ์€ ๋‹น์‹ ์ด ๋งŒ๋“  ์ปดํฌ๋„ŒํŠธ๋ฅผ ์žฌ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๊ฒŒ ํ•ด์ค€๋‹ค. HTML tag๋Š” ์†Œ๋ฌธ์ž๋กœ ์ œ๊ณต๋˜๊ฒŒ์— ๋ฆฌ์•กํŠธ๊ฐ€ ์•Œ์•„์ฐจ๋ฆด ์ˆ˜ ์žˆ๋‹ค. ๊ทธ๋ž˜์„œ ๋‹น์‹ ์ด ๋งŒ๋“  ์ปดํฌ๋„ŒํŠธ๋Š” ๋Œ€๋ฌธ์ž๋กœ ์‹œ์ž‘ํ•ด์•ผ ํ•œ๋‹ค.

  • ์ปดํฌ๋„ŒํŠธ ํ•จ์ˆ˜ ๋‚ด๋ถ€์—์„œ ๋‹ค๋ฅธ ์ปดํฌ๋„ŒํŠธ ํ•จ์ˆ˜๋ฅผ ์ •์˜ํ•˜๋Š” ๊ฒƒ์€ ์ ˆ๋Œ€ ๊ธˆ์ง€๋‹ค! ๋ชจ๋“  ์ปดํฌ๋„ŒํŠธ๋Š” ๋ฐ˜๋“œ์‹œ ์ตœ์ƒ๋‹จ์—์„œ ์ •์˜๋˜์–ด์•ผ ํ•œ๋‹ค.

React ์–ดํ”Œ๋ฆฌ์ผ€์ด์…˜์€ root ์ปดํฌ๋„ŒํŠธ์—์„œ ์‹œ์ž‘๋œ๋‹ค. CRA๋ฅผ ์‚ฌ์šฉํ•˜๋Š” ๊ฒฝ์šฐ, src/App.jsx๊ฐ€ root ์ปดํฌ๋„ŒํŠธ์ด๋ฉฐ Next.js ํ”„๋ ˆ์ž„์›Œํฌ๋ฅผ ์‚ฌ์šฉํ•˜๋Š” ๊ฒฝ์šฐ, pages/inex.jsx๊ฐ€ root ์ปดํฌ๋„ŒํŠธ์ด๋‹ค. ๋Œ€๋ถ€๋ถ„์˜ React ์•ฑ์€ ๋ชจ๋“  ๋ถ€๋ถ„์—์„œ ์ปดํฌ๋„ŒํŠธ๋ฅผ ์‚ฌ์šฉํ•œ๋‹ค. ์•„์ฃผ ์ž‘์€ ๋‹จ์œ„๋ถ€ํ„ฐ ํŽ˜์ด์ง€์™€ ๊ฐ™์€ ํฐ ๋‹จ์œ„๊นŒ์ง€! ์ปดํฌ๋„ŒํŠธ๊ฐ€ ๋‹จ ํ•œ๋ฒˆ๋งŒ ์‚ฌ์šฉ๋œ๋‹ค๊ณ  ํ•˜๋”๋ผ๋„ ๋ฆฌ์•กํŠธ ์ปดํฌ๋„ŒํŠธ๋ฅผ ํ†ตํ•ด ์ž‘์„ฑํ•˜๋Š” ๊ฒƒ์€ UI ์ฝ”๋“œ์™€ ๋งˆํฌ์—…์„ ์ •๋ฆฌํ•˜๋Š” ํŽธ๋ฆฌํ•œ ๋ฐฉ๋ฒ•์ด๋‹ค.
React ๊ธฐ๋ฐ˜์˜ ๋งŽ์€ ํ”„๋ ˆ์ž„์›Œํฌ๋“ค์€ ๋นˆ HTML ํŒŒ์ผ์„ ์‚ฌ์šฉํ•˜๊ณ  JS๋กœ ํŽ˜์ด์ง€ ๊ด€๋ฆฌ๋ฅผ ๋Œ€์‹  ์ˆ˜ํ–‰ํ•˜๋„๋ก ํ•˜๋Š” ๋Œ€์‹ , React ์ปดํฌ๋„ŒํŠธ์—์„œ HTML์„ ์ž๋™์œผ๋กœ ์ƒ์„ฑํ•˜๊ธฐ๋„ ํ•œ๋‹ค. ๊ทธ๋Ÿผ์œผ๋กœ์จ JS ์ฝ”๋“œ๊ฐ€ ๋กœ๋“œ๋˜๊ธฐ ์ „์— ์•ฑ์—์„œ ์ผ๋ถ€ ์ปจํ…์ธ ๋ฅผ ํ‘œ์‹œํ•  ์ˆ˜ ์žˆ๋‹ค.

2. Importing and Exporting Components

The root component file

  • React์—์„œ๋Š” App.js๋ผ๋Š” root ์ปดํฌ๋„ŒํŠธ ํŒŒ์ผ์ด ์กด์žฌํ•œ๋‹ค. ์„ค์ •์— ๋”ฐ๋ผ์„œ ๋‹ค๋ฅธ ํŒŒ์ผ์— ์กด์žฌํ•  ์ˆ˜๋„ ์žˆ๋‹ค. ํ•œํŽธ NEXT.js์—์„œ๋Š” ํŽ˜์ด์ง€ ๋ณ„๋กœ root ์ปดํฌ๋„ŒํŠธ๊ฐ€ ๋‹ค๋ฅผ ์ˆ˜ ์žˆ๋‹ค.

Exporting and importing a component

  • ์ปดํฌ๋„ŒํŠธ๋ฅผ ๋‹ค๋ฅธ ํŒŒ์ผ์—์„œ ์‚ฌ์šฉํ•˜๋ ค๋ฉด, ์ปดํฌ๋„ŒํŠธ๋ฅผ exportํ•ด์•ผ ํ•œ๋‹ค. ๊ทธ๋ฆฌ๊ณ  ๊ทธ ์ปดํฌ๋„ŒํŠธ๋ฅผ ์‚ฌ์šฉํ•˜๊ณ  ์‹ถ์€ ํŒŒ์ผ์—์„œ importํ•ด์•ผ ํ•œ๋‹ค.

React์—์„œ๋Š” โ€˜Gallery.jsโ€™์™€ โ€˜./Galleryโ€™ ๋ชจ๋‘ ์‚ฌ์šฉ ๊ฐ€๋Šฅํ•˜์ง€๋งŒ, ์ „์ž์˜ ๊ฒฝ์šฐ๊ฐ€ ESM ๋ฐฉ์‹์— ๋” ๊ฐ€๊น๋‹ค.

Exporting and importing multiple components from the same file

  • ํ•˜๋‚˜์˜ ํŒŒ์ผ์—์„œ default export์™€ named export๋ฅผ ๋™์‹œ์— ์‚ฌ์šฉ ๊ฐ€๋Šฅํ•˜๋‹ค.

Writing Markup with JSX

  • JSX๋Š” JS๋ฅผ ํ™•์žฅํ•œ ๋ฌธ๋ฒ•์ด๋‹ค. JS ํŒŒ์ผ ์•ˆ์— HTML๊ณผ ์œ ์‚ฌํ•œ ๋งˆํฌ์—…์„ ์ž‘์„ฑํ•  ์ˆ˜ ์žˆ๋„๋ก ํ•ด์ค€๋‹ค. ์ปดํฌ๋„ŒํŠธ๋ฅผ ์ž‘์„ฑํ•˜๋Š” ๋‹ค๋ฅธ ๋ฐฉ๋ฒ•๋„ ์žˆ์ง€๋งŒ, ๋ณดํŽธ์ ์œผ๋กœ JSX๊ฐ€ ์‚ฌ์šฉ๋œ๋‹ค.

React.createElement('div', null, Hello ${this.props.toWhat});๊ณผ ๊ฐ™์ด JSX๋ฅผ ์‚ฌ์šฉํ•˜์ง€ ์•Š๊ณ  ์ปดํฌ๋„ŒํŠธ๋ฅผ ์ž‘์„ฑํ•  ์ˆ˜๋„ ์žˆ๋‹ค.

JSX: Putting markup into JavaScript

  • ๊ธฐ์กด์˜ ์›น์€ HTML๋กœ ์ปจํ…์ธ , CSS๋กœ ๋””์ž์ธ, JS๋กœ ๋กœ์ง์„ ์ž‘์„ฑํ•ด์™”๋‹ค. ์ด๋ ‡๋“œ ๋ณดํ†ต์€ ๋ถ„๋ฆฌ๋œ ํŒŒ์ผ๋กœ ๊ฐ๊ฐ ๊ด€๋ฆฌํ•˜์˜€๋‹ค.
  • ์›น์ด ๋ฐœ์ „ํ•˜๊ณ  ๋”์šฑ๋” interactiveํ•ด์ง€๋ฉด์„œ ๋กœ์ง์ด ์ปจํ…์ธ ๋ฅผ ๊ฒฐ์ •ํ•˜๋Š” ๊ฒฝ์šฐ๊ฐ€ ์ฆ๊ฐ€ํ–ˆ๋‹ค. ๊ทธ๋Ÿฌ๋ฉด์„œ JS๊ฐ€ HTML๋„ ๋‹ด๋‹นํ•˜๊ฒŒ ๋˜์—ˆ๊ณ  ์ด๊ฒŒ ๋ฐ”๋กœ React ์ปดํฌ๋„ŒํŠธ์— ๋ Œ๋”๋ง ๋กœ์ง๊ณผ ๋งˆํฌ์—…์ด ํ•จ๊ป˜ ๋“ค์–ด๊ฐ€๊ฒŒ ๋œ ์ด์œ ์ด๋‹ค.
  • ๊ฐ React ์ปดํฌ๋„ŒํŠธ๋Š” ๋ธŒ๋ผ์šฐ์ €์— ๋ Œ๋”๋ง๋  ๋งˆํฌ์—…์„ ๋ฐ˜ํ™˜ํ•˜๋Š” ํ•จ์ˆ˜์ด๋‹ค. React ์ปดํฌ๋„ŒํŠธ๋Š” JSX๋ผ๋Š” ๊ตฌ๋ฌธ ํ™•์žฅ์ž(JS ๊ฐ์ฒด)๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ํ•ด๋‹นํ•˜๋Š” ๋งˆํฌ์—…์„ ํ‘œํ˜„ํ•œ๋‹ค. HTML๊ณผ ์œ ์‚ฌํ•ด๋ณด์ด์ง€๋งŒ ๋” ์—„๊ฒฉํ•˜๊ณ  ๋™์ ์œผ๋กœ ์ •๋ณด๋ฅผ ํ‘œ์‹œํ•  ์ˆ˜ ์žˆ๋‹ค.

JSX์™€ React๋Š” ๋ณ„๊ฐœ์˜ ๊ฐœ๋…์ด๋‹ค. ์‚ฌ์‹ค์ƒ ํ•จ๊ป˜ ์‚ฌ์šฉ๋˜๊ธฐ๋Š” ํ•˜์ง€๋งŒ ๋…๋ฆฝ์ ์œผ๋กœ ์‚ฌ์šฉ๋„ ๊ฐ€๋Šฅํ•˜๋‹ค. JSX๋Š” ๊ตฌ๋ฌธ ํ™•์žฅ, React๋Š” JS ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ์ด๋‹ค.

The Rules of JSX

1. Return a single root element

  • JSX๋Š” ๋ฐ˜๋“œ์‹œ ํ•˜๋‚˜์˜ ๋ฃจํŠธ ์—˜๋ฆฌ๋จผํŠธ๋ฅผ ๋ฐ˜ํ™˜ํ•ด์•ผ ํ•œ๋‹ค. ์—ฌ๋Ÿฌ ์—˜๋ฆฌ๋จผํŠธ๋ฅผ ๋ฐ˜ํ™˜ํ•˜๋ ค๋ฉด, React.Fragment(<></>)๋ฅผ ์‚ฌ์šฉํ•˜๋ฉด ๋œ๋‹ค.

์™œ ํ•˜๋‚˜์˜ ์—˜๋ฆฌ๋จผํŠธ๋ฅผ ๋ฐ˜ํ™˜ํ•ด์•ผํ• ๊นŒ??
JSX๋Š” ๊ฒฐ๊ตญ JS ๊ฐ์ฒด์ด๋‹ค. ํ—Œ๋ฐ ํ•˜๋‚˜์˜ ์—˜๋ฆฌ๋จผํŠธ๋กœ ๊ฐ์‹ธ์ง€ ์•Š์œผ๋ฉด ๋งˆ์น˜ ๋ฐฐ์—ด์„ ๊ฐ์‹ธ์ง€ ์•Š๊ณ  ํ•œ๋ฒˆ์— ์—ฌ๋Ÿฌ๊ฐœ์˜ ์›์†Œ๋ฅผ returnํ•˜๊ฒ ๋‹ค๋Š” ๊ฒƒ๊ณผ ๋™์ผํ•˜๋‹ค.

2. Close all the tags

  • ๋ฐ˜๋“œ์‹œ ํƒœ๊ทธ๋ฅผ ๋ช…์‹œ์ ์œผ๋กœ ๋‹ซ์•„์•ผ ํ•œ๋‹ค.

3. camelCase all most of the things!

  • JSX๋Š” ๊ฒฐ๊ตญ JS ๊ฐ์ฒด์ด๊ณ  ์ด ์•ˆ์—์„œ ์ž‘์„ฑ๋œ ์–ดํŠธ๋ฆฌ๋ทฐํŠธ๋“ค์€ ์ด ๊ฐ์ฒด์˜ key๊ฐ€ ๋œ๋‹ค. ๊ทธ๋ ‡๊ธฐ ๋•Œ๋ฌธ์— camelCase๋กœ ์ž‘์„ฑํ•˜๋Š” ๊ฒƒ์„ ๊ถŒ์žฅํ•œ๋‹ค.
  • ๋˜ํ•œ ์ผ๋ฐ˜ HTML ํƒœ๊ทธ์˜ ์–ดํŠธ๋ฆฌ๋ทฐํŠธ ์ค‘ class๋ฅผ ๋Œ€์ฒดํ•˜๋Š” ๊ฒƒ์€ className์œผ๋กœ ์ด๋Š” JS์— ์ด๋ฏธ ์กด์žฌํ•˜๋Š” class ์˜ˆ์•ฝ์–ด๋•Œ๋ฌธ์ด๋‹ค.

JavaScript in JSX with Curly Braces

  • JSX๋กœ ์ž‘์„ฑํ•œ ๋งˆํฌ์—… ์•ˆ์— JS ๋กœ์ง์„ ์ถ”๊ฐ€ํ•˜๊ฑฐ๋‚˜ ๋™์ ์ธ ๊ฐ’์„ ํ‘œํ˜„ํ•˜๊ณ  ์‹ถ์„ ๋•Œ, ์ค‘๊ด„ํ˜ธ{}๋ฅผ ์‚ฌ์šฉํ•œ๋‹ค.

Using โ€œdouble curliesโ€: CSS and other objects in JSX

  • ์ข…์ข… ์ค‘๊ด„ํ˜ธ ์•ˆ์— ์ค‘๊ด„ํ˜ธ๋ฅผ ์‚ฌ์šฉํ•ด์•ผ ํ•  ๋•Œ๊ฐ€ ์žˆ๋‹ค. ์˜ˆ๋ฅผ ๋“ค์–ด, CSS๋ฅผ ์ž‘์„ฑํ•  ๋•Œ, ์ค‘๊ด„ํ˜ธ ์•ˆ์— ๊ฐ์ฒด๋ฅผ ์ž‘์„ฑํ•ด์•ผ ํ•œ๋‹ค. ์ด๋•Œ, ์ค‘๊ด„ํ˜ธ๋ฅผ ๋‘๋ฒˆ ์‚ฌ์šฉํ•˜๋ฉด ๋œ๋‹ค.(์€๊ทผ ์ž˜ ํ—ท๊ฐˆ๋ฆฐ๋‹ค.)
  • ๋ฐ˜๋“œ์‹œ JSX์—์„œ ๊ฐ€์žฅ ๋ฐ”๊นฅ {}๋Š” JS ์ฝ”๋“œ๋ฅผ ์ž‘์„ฑํ•˜๊ธฐ ์œ„ํ•œ ๊ฒƒ์ด๊ณ , ์•ˆ์ชฝ {}๋Š” ๊ฐ์ฒด๋ฅผ ์ž‘์„ฑํ•˜๊ธฐ ์œ„ํ•œ ๊ฒƒ์ด๋ผ๋Š” ๊ฒƒ์„ ๊ธฐ์–ตํ•˜์ž.

style ์ „๋‹ฌ์„ ์œ„ํ•œ ๊ฐ์ฒด์˜ key๊ฐ’์€ camelCase๋กœ ์ž‘์„ฑํ•ด์•ผ ํ•œ๋‹ค.

Passing Props to a Component

  • React ์ปดํฌ๋„ŒํŠธ๋Š” props๋ฅผ ์ด์šฉํ•ด ์„œ๋กœ ํ†ต์‹ ํ•œ๋‹ค.(๊ฐ’์„ ์ฃผ๊ณ  ๋ฐ›๋Š”๋‹ค.) ๋ถ€๋ชจ ์ปดํฌ๋„ŒํŠธ๋Š” props๋ฅผ ์ „๋‹ฌํ•จ์œผ๋กœ์จ ์ •๋ณด๋ฅผ ์ž์‹ ์ปดํฌ๋„ŒํŠธ์—๊ฒŒ ์ „๋‹ฌํ•  ์ˆ˜ ์žˆ๋‹ค.
  • props๋Š” HTML ์–ดํŠธ๋ฆฌ๋ทฐํŠธ(์†์„ฑ)์„ ๋– ์˜ค๋ฅด๊ฒŒ ํ•˜์ง€๋งŒ, JS์˜ ๋ชจ๋“  ๊ฐ’์„ ์ „๋‹ฌํ•  ์ˆ˜ ์žˆ๋‹ค.

Familiar props

function Avatar() {
  return (
    <img
      className="avatar"
      src="https://i.imgur.com/1bX5QH6.jpg"
      alt="Lin Lanying"
      width={100}
      height={100}
    />
  );
}
  • ์œ„์˜ ์ฝ”๋“œ์—์„œ src, alt, width, height๋Š” ๋ชจ๋‘ props์ด๋‹ค. ์ด๋Š” HTML์˜ ์–ดํŠธ๋ฆฌ๋ทฐํŠธ์™€ ์œ ์‚ฌํ•˜๋‹ค.

์•„๋ž˜์™€ ๊ฐ™์€ ๋ฐฉ์‹์œผ๋กœ ๋ถ€๋ชจ๊ฐ€ ์ „๋‹ฌํ•œ props๋ฅผ ๋ฐ›์•„์„œ ์ž์‹์ด ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๋‹ค.

import { getImageUrl } from './utils.js';

// ๊ฐœ์ธ์ ์œผ๋กœ ๋‚ด๊ฐ€ ์ข‹์•„ํ•˜๋Š” ๋ฐฉ๋ฒ•
function Avatar(props) {
  const { person, size } = props;
  return (
    <img
      className="avatar"
      src={getImageUrl(person)}
      alt={person.name}
      width={size}
      height={size}
    />
  );
}

// ํŒŒ๋ผ๋ฏธํ„ฐ๋กœ ๋ฐ”๋กœ ๊ตฌ์กฐ๋ถ„ํ•ดํ• ๋‹นํ•˜๋Š” ๋ฐฉ๋ฒ•
function Avatar({ person, size }) {
  return (
    <img
      className="avatar"
      src={getImageUrl(person)}
      alt={person.name}
      width={size}
      height={size}
    />
  );
}

export default function Profile() {
  return (
    <div>
      <Avatar
        size={100}
        person={{
          name: 'Katsuko Saruhashi',
          imageId: 'YfeOqp2'
        }}
      />
    </div>
  );
}
  • props๋Š” ์ปดํฌ๋„ŒํŠธ์—์„œ ์ „๋‹ฌํ•  ์ˆ˜ ์žˆ๋Š” ์œ ์ผํ•œ ํ•จ์ˆ˜์˜ ํŒŒ๋ผ๋ฏธํ„ฐ์ด๋‹ค.

Forwarding props with the JSX spread syntax

  • props๋ฅผ ์ „๋‹ฌํ•  ๋•Œ, ์ „๋‹ฌํ•˜๊ณ  ์‹ถ์€ props์˜ ๊ฐœ์ˆ˜๊ฐ€ ๋งŽ์•„์ง€๋ฉด ๋ฒˆ๊ฑฐ๋กญ๋‹ค. ์ด๋•Œ, JSX spread syntax๋ฅผ ์‚ฌ์šฉํ•˜๋ฉด ํŽธ๋ฆฌํ•˜๋‹ค.
function Profile({ person, size, isSepia, thickBorder }) {
  return (
    <div className="card">
      <Avatar
        person={person}
        size={size}
        isSepia={isSepia}
        thickBorder={thickBorder}
      />
    </div>
  );
}

// ๋ถ€๋ชจ ์ปดํฌ๋„ŒํŠธ์˜ ๋ชจ๋“  props๋ฅผ ์ „๋‹ฌํ•œ๋‹ค๋ฉด ์•„๋ž˜์™€ ๊ฐ™์ด ์“ฐ๋Š” ๊ฒŒ ๋” ๊น”๋”ํ•  ์ˆ˜ ์žˆ๋‹ค.
function Profile(props) {
  return (
    <div className="card">
      <Avatar {...props} />
    </div>
  );
}

Passing JSX as children

  • ์ปดํฌ๋„ŒํŠธ๋ฅผ ์‚ฌ์šฉํ•  ๋•Œ, <Avatar />์ฒ˜๋Ÿผ ํƒœ๊ทธ๋ฅผ ์‚ฌ์šฉํ•˜๋Š” ๊ฒƒ์ด ์•„๋‹ˆ๋ผ, <Avatar></Avatar>์ฒ˜๋Ÿผ ์‚ฌ์šฉํ•  ์ˆ˜๋„ ์žˆ๋‹ค. ์ด๋•Œ, ์ปดํฌ๋„ŒํŠธ์˜ children์ด๋ผ๋Š” props์— JSX๋ฅผ ์ „๋‹ฌํ•  ์ˆ˜ ์žˆ๋‹ค.
import Avatar from './Avatar.js';

// Card ์ปดํฌ๋„ŒํŠธ๋Š” ๋‚ด๋ถ€์—์„œ ๋ฌด์—‡์ด ๋ Œ๋”๋ง๋˜๋Š”์ง€ ์•Œ ํ•„์š”๊ฐ€ ์—†๋‹ค.
function Card({ children }) {
  return (
    <div className="card">
      {children}
    </div>
  );
}

export default function Profile() {
  return (
    <Card>
      <Avatar
        size={100}
        person={{ 
          name: 'Katsuko Saruhashi',
          imageId: 'YfeOqp2'
        }}
      />
    </Card>
  );
}
  • ์‹œ๊ฐ์  ๋ž˜ํผ์— ๋Œ€ํ•œ ์ปดํฌ๋„ŒํŠธ๋ฅผ ๋งŒ๋“ค ๋•Œ, children์„ ์‚ฌ์šฉํ•˜๋ฉด ์œ ์šฉํ•˜๋‹ค.
import Avatar from './Avatar.js';

function Card({ children }) {
  return (
    <div className="card">
      {children}
    </div>
  );
}

function CardWithAvatar({ children }) {
  return (
    <Card>
      <Avatar size={100} />
      {children}
    </Card>
  );
}

export default function Profile() {
  return (
    <CardWithAvatar>
      <h1>Katsuko Saruhashi</h1>
      <p>Chemist</p>
    </CardWithAvatar>
  );
}

How props change over time

  • ์ปดํฌ๋„ŒํŠธ๋Š” props๋ฅผ ํ†ตํ•ด ์ •๋ณด๋ฅผ ์ „๋‹ฌ๋ฐ›๋Š”๋‹ค. ์ด๋•Œ, props๋Š” immutableํ•˜๋‹ค. ์ฆ‰, ์ปดํฌ๋„ŒํŠธ๊ฐ€ ๋ Œ๋”๋ง๋˜๋Š” ๋™์•ˆ props๋Š” ๋ณ€ํ•˜์ง€ ์•Š๋Š”๋‹ค.
  • ๋ฐ˜๋“œ์‹œ props์— ๋Œ€ํ•œ ๋ณ€๊ฒฝ์„ ์‹œ๋„ํ•˜์ง€ ๋ง์ž. ์ปดํฌ๋„ŒํŠธ๊ฐ€ ๋ Œ๋”๋ง๋˜๋Š” ๋™์•ˆ props๋Š” ๋ณ€ํ•˜์ง€ ์•Š๋Š”๋‹ค๋Š” ๊ฒƒ์„ ๊ธฐ์–ตํ•˜์ž.
  • ์–ด๋–ค ๋ณ€๊ฒฝ์„ ์œ„ํ•œ ์ •๋ณด๋ฅผ ์ „๋‹ฌํ•˜๊ณ  ์‹ถ๋‹ค๋ฉด, state๋ฅผ ์‚ฌ์šฉํ•˜์ž.

Conditional Rendering

  • ์–ด๋–ค ์กฐ๊ฑด์— ๋”ฐ๋ผ ๋‹ค๋ฅธ UI๋ฅผ ๋ณด์—ฌ์ค˜์•ผํ•˜๋Š” ๊ฒฝ์šฐ๋กœ ๋ฆฌ์•กํŠธ์—์„œ๋Š” ์ฃผ๋กœ if ๋ฌธ, && ์—ฐ์‚ฐ์ž(๋…ผ๋ฆฌ ์—ฐ์‚ฐ์ž), ?์™€ : ์—ฐ์‚ฐ์ž(์‚ผํ•ญ ์—ฐ์‚ฐ์ž)๋ฅผ ์‚ฌ์šฉํ•œ๋‹ค.
  • null!!! ๋ฆฌ์•กํŠธ์—์„œ null์€ ์•„๋ฌด๊ฒƒ๋„ ๋ Œ๋”๋งํ•˜์ง€ ์•Š๋Š”๋‹ค.(null์€ ์•„๋ฌด๊ฒƒ๋„ ๋ Œ๋”๋งํ•˜์ง€ ์•Š๊ฒ ๋‹ค๋Š” ์˜๋ฏธ์ด๋‹ค.)

null์€ ์•„๋ฌด๊ฒƒ๋„ ๋ Œ๋”๋งํ•˜์ง€ ์•Š๋Š”๋‹ค๋Š” ์ ์„ ์ด์šฉํ•˜๋ฉด, ์กฐ๊ฑด๋ถ€ ๋ Œ๋”๋ง์„ ํ•  ์ˆ˜ ์žˆ๋‹ค.

function Profile({ person }) {
  if (person === null) {
    return null;
  }

  return (
    <div>
      <Avatar person={person} />
      <div>{person.name}</div>
    </div>
  );
}
  • ์‚ผํ•ญ์—ฐ์‚ฐ์ž๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ์กฐ๊ฑด๋ถ€ ๋ Œ๋”๋ง์„ ํ•  ์ˆ˜ ์žˆ๋‹ค. ๋‹จ, ๋„ˆ๋ฌด ์žฆ์€ ์‚ผํ•ญ์—ฐ์‚ฐ์ž ์‚ฌ์šฉ์€ ๊ฐ€๋…์„ฑ์„ ๋‚ฎ์ถœ ์ˆ˜ ์žˆ๊ธฐ์— ์ž์‹ ์ปดํฌ๋„ŒํŠธ๋ฅผ ์ถ”์ถœํ•˜์—ฌ ์ •๋ฆฌํ•˜๋Š” ๊ฒƒ์„ ๊ณ ๋ คํ•˜๋Š” ๊ฒŒ ์ข‹๋‹ค.
function Profile({ person }) {
  return (
    <div>
      {person !== null ? (
        <>
          <Avatar person={person} />
          <div>{person.name}</div>
        </>
      ) : null}
    </div>
  );
}
  • ๋…ผ๋ฆฌ์—ฐ์‚ฐ์ž(&&)๋Š” ์ฃผ๋กœ ์กฐ๊ฑด์ด ์ฐธ์ผ ๋•Œ ์ผ๋ถ€ JSX๋ฅผ ๋ Œ๋”๋งํ•˜๊ณ  ๊ทธ๋ ‡์ง€ ์•Š์œผ๋ฉด ์•„๋ฌด๊ฒƒ๋„ ๋ Œ๋”๋งํ•˜์ง€ ์•Š์œผ๋ ค ํ•  ๋•Œ ์ž์ฃผ ์‚ฌ์šฉ๋œ๋‹ค.
function Profile({ person }) {
  return (
    <div>
      {person !== null && (
        <>
          <Avatar person={person} />
          <div>{person.name}</div>
        </>
      )}
    </div>
  );
}

&&์˜ ์™ผ์ชฝ์— ์ˆซ์ž๊ฐ€ ์˜ค๊ฒŒ ํ•˜์ง€ ๋ง์ž! ์˜ˆ๋ฅผ ๋“ค์–ด ์šฐ๋ฆฌ๋Š” ํ”ํžˆ 0์ด falsyํ•˜๊ธฐ ๋•Œ๋ฌธ์— 0์ด ์˜ค๋ฉด 0์ด ๋ Œ๋”๋ง๋˜์ง€ ์•Š๋Š”๋‹ค๊ณ  ์ƒ๊ฐํ•  ์ˆ˜ ์žˆ๋‹ค. ํ•˜์ง€๋งŒ 0์€ falsyํ•˜์ง€๋งŒ false๋Š” ์•„๋‹ˆ๊ธฐ ๋•Œ๋ฌธ์— 0์ด ๋ Œ๋”๋ง๋œ๋‹ค.

function Example() {
  return (
    <div>
      {0 && <div>zero</div>}
      {false && <div>zero</div>}
    </div>
  );
}

์ด๋Ÿด ๋• 0์˜ ํ‘œํ˜„์„ true/false๋กœ ๋ฐ”๊ฟ”์ฃผ๋ฉด ๋œ๋‹ค.

function Example() {
  return (
    <div>
      {!!0 && <div>zero</div>}
      {!!false && <div>zero</div>}
    </div>
  );
}

Rendering Lists

  • ์šฐ๋ฆฌ๊ฐ€ ๊ฐ–๊ณ  ์žˆ๋Š” ๋ฐ์ดํ„ฐ ๋ชจ์Œ์—์„œ ์œ ์‚ฌํ•œ ์ปดํฌ๋„ŒํŠธ๋ฅผ ์—ฌ๋Ÿฌ ๊ฐœ ๋ Œ๋”๋งํ•˜๊ณ  ์‹ถ์„ ๋•Œ๊ฐ€ ์žˆ๋‹ค. ์ด๋•Œ, map ํ˜น์€ filter์„ ์‚ฌ์šฉํ•˜๋ฉด ๋œ๋‹ค.
function ProfileList({ profiles }) {
  return (
    <div>
      {profiles.map((profile) => (
        <Profile person={profile} />
      ))}
    </div>
  );
}

Keeping list items in order with key

  • ๋ฐฐ์—ด ํ˜•ํƒœ์˜ ๋ฐ์ดํ„ฐ๋ฅผ map, filter ๋“ฑ์œผ๋กœ ์ปดํฌ๋„ŒํŠธ๋กœ ํ‘œํ˜„ํ•  ๋•Œ, key๋ฅผ ์ง€์ •ํ•ด์ฃผ์ง€์•Š์œผ๋ฉด ์•„๋ž˜์™€ ๊ฐ™์€ ๊ฒฝ๊ณ  ๋ฉ”์‹œ์ง€๋ฅผ ํ™•์ธํ•  ์ˆ˜ ์žˆ๋‹ค.
Warning: Each child in a list should have a unique โ€œkeyโ€ prop. 
๊ฒฝ๊ณ : ๋ชฉ๋ก์˜ ๊ฐ ์ž์‹์—๋Š” ๊ณ ์œ ํ•œ โ€œkeyโ€ prop์ด ์žˆ์–ด์•ผ ํ•ฉ๋‹ˆ๋‹ค.
  • map() ํ˜ธ์ถœ ๋‚ด๋ถ€์˜ JSX ์š”์†Œ์—๋Š” ํ•ญ์ƒ ๊ณ ์œ ํ•œ key prop์„ ์ง€์ •ํ•ด์•ผ ํ•œ๋‹ค.
  • key๋Š” ๊ฐ ์ปดํฌ๋„ŒํŠธ๊ฐ€ ์–ด๋–ค ๋ฐฐ์—ด ํ•ญ๋ชฉ์— ํ•ด๋‹นํ•˜๋Š”์ง€ ๋ฆฌ์•กํŠธ์— ์•Œ๋ ค์ฃผ์–ด ๋‚˜์ค‘์— ๋งค์นญํ•  ์ˆ˜ ์žˆ๋„๋ก ํ•œ๋‹ค. ๋ฐฐ์—ด์ด ์ •๋ ฌ๋˜์–ด ๊ทธ ๋‚ด๋ถ€ ๋ฐ์ดํ„ฐ๊ฐ€ ์ด๋™ํ•˜๊ฑฐ๋‚˜, ์‚ฝ์ž…, ์‚ญ์ œ๋˜๋Š” ๊ฒฝ์šฐ key๋ฅผ ๊ธฐ๋ฐ˜์œผ๋กœ ์ถ”์ ํ•œ๋‹ค.
  • key๊ฐ’์€ ํ”„๋ก ํŠธ์—”๋“œ์—์„œ ์ฆ‰์„์œผ๋กœ ์ƒ์„ฑํ•˜๋Š” ๊ฒƒ์ด ์•„๋‹Œ, ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค์—์„œ ๊ฐ€์ ธ์˜จ ๋ฐ์ดํ„ฐ์˜ ๊ณ ์œ ํ•œ ์‹๋ณ„์ž๋ฅผ ์‚ฌ์šฉํ•˜๋Š” ๊ฒƒ์ด ์ข‹๋‹ค.(๋กœ์ปฌ์—์„œ ์ƒ์„ฑ๋œ ๋ฐ์ดํ„ฐ๋ฅผ ์‚ฌ์šฉํ•˜๋Š” ๊ฒฝ์šฐ crypto.randomUUID() ํ˜น์€ uuid๋ฅผ ์‚ฌ์šฉํ•˜๋Š” ๊ฒƒ์ด ์ข‹๋‹ค.)
function ProfileList({ profiles }) {
  return (
    <div>
      {profiles.map((profile) => (
        <Profile key={profile.id} person={profile} />
      ))}
    </div>
  );
}

Fragment(<></>)์—๋Š” key๊ฐ’์„ ์ „๋‹ฌํ•  ์ˆ˜ ์—†์œผ๋ฏ€๋กœ, ๋ฆฌ์•กํŠธ์—์„œ ์‚ฌ์šฉํ•˜๋Š” Fragment๋ฅผ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๋‹ค.

Rules of keys

  • key๋Š” ํ˜•์ œ ๊ฐ„์— ๊ณ ์œ ํ•ด์•ผ ํ•œ๋‹ค. ๋‹น์—ฐํžˆ ๋‹ค๋ฅธ ๋ฐ์ดํ„ฐ ๋ฐฐ์—ด์˜ JSX ๋…ธ๋“œ์—๋Š” ๋™์ผํ•œ key๋ฅผ ์‚ฌ์šฉํ•ด๋„ ๊ดœ์ฐฎ๋‹ค.
  • key๊ฐ€ ๋ณ€๊ฒฝ๋˜์ง€ ์•Š์•„์•ผ ํ•œ๋‹ค. key๋Š” ์ปดํฌ๋„ŒํŠธ์˜ props์™€ state์— ์˜์กดํ•ด์„œ๋Š” ์•ˆ๋œ๋‹ค. key๋Š” ์ปดํฌ๋„ŒํŠธ๊ฐ€ ๋ Œ๋”๋ง๋  ๋•Œ๋งˆ๋‹ค ๊ณ ์œ ํ•œ ๊ฐ’์ด์–ด์•ผ ํ•œ๋‹ค.

Why does React need keys???

  • ๋ฐ์Šคํฌํ†ฑ ํŒŒ์ผ์— ์ด๋ฆ„ ๋Œ€์‹  ์ˆœ์„œ๊ฐ€ ์ ํ˜€์žˆ๋‹ค๊ณ  ์ƒ๊ฐํ•ด๋ณด์ž. ์ฒ˜์Œ์—” ๋‚˜์˜์ง€ ์•Š์ง€๋งŒ, ์ฒซ๋ฒˆ์งธ ํŒŒ์ผ์ด ์ง€์›Œ์ง€๋ฉด ๋‘๋ฒˆ์งธ ํŒŒ์ผ์ด ๊ณง ์ฒซ๋ฒˆ์งธ ํŒŒ์ผ์ด ๋œ๋‹ค. ์ฆ‰, ํ—ท๊ฐˆ๋ฆฌ๊ฒŒ ๋œ๋‹ค.(๊ทธ๋ƒฅ ๋ฐฐ์—ด์˜ index๋กœ key๋ฅผ ์ง€์ •ํ•˜๋ฉด ์ด๋Ÿฐ ๋ฌธ์ œ๊ฐ€ ๋ฐœ์ƒํ•œ๋‹ค.)
  • ์ด ๋•Œ, ํด๋”์˜ ํŒŒ์ผ ์ด๋ฆ„๊ณผ JSX key๋Š” ๋น„์Šทํ•œ ์—ญํ• ์„ ํ•œ๋‹ค. key๋ฅผ ์‚ฌ์šฉํ•˜๋ฉด ํ˜•์ œ ํ•ญ๋ชฉ ์‚ฌ์ด์—์„œ ํŠน์ • ํ•ญ๋ชฉ์„ ๊ณ ์œ ํ•˜๊ฒŒ ์‹๋ณ„ํ•  ์ˆ˜ ์žˆ๋‹ค. ๋ฐ์ดํ„ฐ ๋‚ด์˜ ๊ณ ์œ ํ•œ id๋ฅผ ํ†ตํ•ด key๋ฅผ ์ง€์ •ํ•˜๊ฒŒ ๋˜๋ฉด ์žฌ์ •๋ ฌ๋กœ ์ธํ•ด ๋ฐ์ดํ„ฐ์˜ ์œ„์น˜๊ฐ€ ๋ณ€๊ฒฝ๋˜๋”๋ผ๋„ key๋Š” ๋ณ€ํ•˜์ง€ ์•Š๊ธฐ ๋•Œ๋ฌธ์— ๋ฌธ์ œ๊ฐ€ ๋ฐœ์ƒํ•˜์ง€ ์•Š๋Š”๋‹ค.

์ ˆ๋Œ€๋กœ key๋ฅผ Math.random()๊ณผ ๊ฐ™์ด ์ฆ‰์„์—์„œ ์ƒ์„ฑํ•˜๋ฉด ์•ˆ๋œ๋‹ค. ๋ Œ๋”๋ง๋  ๋•Œ๋งˆ๋‹ค ์ƒˆ๋กœ์šด key๊ฐ€ ์ƒ์„ฑ๋˜๊ธฐ ๋•Œ๋ฌธ์— ์ปดํฌ๋„ŒํŠธ๊ฐ€ ๋ถˆํ•„์š”ํ•˜๊ฒŒ ๋ฆฌ๋ Œ๋”๋ง๋˜๊ณ  ์„ฑ๋Šฅ์ด ์ €ํ•˜๋œ๋‹ค.
์ปดํฌ๋„ŒํŠธ๋Š” key๋ฅผ prop์œผ๋กœ ๋ฐ›์ง€ ์•Š๋Š”๋‹ค. ๋งŒ์•ฝ ์ž์‹ ์ปดํฌ๋„ŒํŠธ์—๊ฒŒ ์–ด๋–ค ๊ณ ์œ ํ•œ id๋ฅผ ์ „๋‹ฌํ•ด์ฃผ๊ณ  ์‹ถ๋‹ค๋ฉด ๋ณ„๋„์˜ prop์œผ๋กœ ์ „๋‹ฌํ•ด์•ผ ํ•œ๋‹ค. <Profile key ={id} userId={id} />

Keeping Components Pure

  • ์ปดํฌ๋„ŒํŠธ๋Š” props์™€ state์— ์˜์กดํ•ด์„œ๋Š” ์•ˆ๋œ๋‹ค. ์ปดํฌ๋„ŒํŠธ๋Š” props์™€ state๊ฐ€ ๋ณ€๊ฒฝ๋˜์ง€ ์•Š์œผ๋ฉด ํ•ญ์ƒ ๋™์ผํ•œ ๊ฒฐ๊ณผ๋ฅผ ๋ Œ๋”๋งํ•ด์•ผ ํ•œ๋‹ค. ์ด๋ฅผ ์ˆœ์ˆ˜ ์ปดํฌ๋„ŒํŠธ๋ผ๊ณ  ํ•œ๋‹ค.

Purity: Components as formulas

  • ์ˆœ์ˆ˜ ์ปดํฌ๋„ŒํŠธ๋Š” ์ˆ˜ํ•™์ ์ธ ํ•จ์ˆ˜์™€ ๋น„์Šทํ•˜๋‹ค. ํ•จ์ˆ˜๋Š” ์ž…๋ ฅ๊ฐ’์ด ๊ฐ™์œผ๋ฉด ํ•ญ์ƒ ๋™์ผํ•œ ๊ฒฐ๊ณผ๋ฅผ ๋ฐ˜ํ™˜ํ•œ๋‹ค. ์ปดํฌ๋„ŒํŠธ๋„ props๊ฐ€ ๊ฐ™์œผ๋ฉด ํ•ญ์ƒ ๋™์ผํ•œ ๊ฒฐ๊ณผ๋ฅผ ๋ Œ๋”๋งํ•œ๋‹ค.
function Profile({ person }) {
  return (
    <div>
      <p>{person.name}</p>
      <p>{person.age}</p>
    </div>
  );
}
  • ์œ„์˜ ์ปดํฌ๋„ŒํŠธ๋Š” ์ˆœ์ˆ˜ ์ปดํฌ๋„ŒํŠธ์ด๋‹ค. props๊ฐ€ ๊ฐ™์œผ๋ฉด ํ•ญ์ƒ ๋™์ผํ•œ ๊ฒฐ๊ณผ๋ฅผ ๋ฐ˜ํ™˜ํ•œ๋‹ค. ๋งŒ์•ฝ props๊ฐ€ ๋ณ€๊ฒฝ๋˜๋ฉด ์ปดํฌ๋„ŒํŠธ๋Š” ๋‹ค์‹œ ๋ Œ๋”๋ง๋œ๋‹ค.

Side Effects: (un)intended consequences

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

Detecting impure calculations with StrictMode

  • ๋ฆฌ์•กํŠธ์—์„œ๋Š” ๋ Œ๋”๋งํ•˜๋Š” ๋™์•ˆ ์ฝ์„ ์ˆ˜ ์žˆ๋Š” ์ž…๋ ฅ๊ฐ’์ด 3๊ฐ€์ง€ ์žˆ๋‹ค. props, state, context. ์ด 3๊ฐ€์ง€ ๊ฐ’์€ ๋ Œ๋”๋ง ์ค‘์—๋งŒ ์ฝ์„ ์ˆ˜ ์žˆ์œผ๋ฉฐ, ๋ Œ๋”๋ง ์ดํ›„์—๋Š” ์ฝ์„ ์ˆ˜ ์—†๋‹ค. ์ด๋ฅผ ์ฝ๊ธฐ ์ „์šฉ์ด๋ผ๊ณ  ํ•œ๋‹ค.
  • ์‚ฌ์šฉ์ž ์ž…๋ ฅ์— ๋Œ€ํ•œ ์‘๋‹ต์œผ๋กœ ๋ฌด์–ธ๊ฐ€๋ฅผ ๋ฐ”๊พธ๋ ค๋ฉด ๋ณ€์ˆ˜ ๋Œ€์‹  state๋ฅผ ์„ค์ •ํ•ด์•ผ ํ•œ๋‹ค. ์ปดํฌ๋„ŒํŠธ๊ฐ€ ๋ Œ๋”๋ง๋˜๋Š” ๋™์•ˆ์—” ๊ธฐ์กด ๋ณ€์ˆ˜, ๊ฐ์ฒด๋ฅผ ์ ˆ๋Œ€ ๋ณ€๊ฒฝํ•ด์„œ๋Š” ์•ˆ๋œ๋‹ค.
  • ๋ฆฌ์•กํŠธ๋Š” ๊ฐœ๋ฐœ ํ™˜๊ฒฝ์—์„œ ๊ฐ ์ปดํฌ๋„ŒํŠธ์˜ ํ•จ์ˆ˜๋ฅผ ๋‘ ๋ฒˆ ํ˜ธ์ถœํ•˜๋Š” Strict Mode๋ฅผ ์ œ๊ณตํ•œ๋‹ค. Strict Mode๋Š” ์ปดํฌ๋„ŒํŠธ ํ•จ์ˆ˜๋ฅผ ๋‘ ๋ฒˆ ํ˜ธ์ถœํ•จ์œผ๋กœ์จ ๊ทœ์น™์„ ์œ„๋ฐ˜ํ•˜๋Š” ์ปดํฌ๋„ŒํŠธ๋ฅผ ์ฐพ์•„๋‚ด๋Š” ๋ฐ ๋„์›€์ด ๋œ๋‹ค.

Where you can cause side effects

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

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

Why does React care about purity?

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

์ฐธ๊ณ