๐ŸŽจ 21. ๋ Œ๋” ํŠธ๋ฆฌ & key์˜ ์ง„์‹ค: ์ปดํฌ๋„ŒํŠธ ๋™์ผ์„ฑ์˜ ๋น„๋ฐ€

๐Ÿ“‹ ๊ฐœ์š”

์ƒํƒœ(State)๊ฐ€ ์‹ค์ œ๋กœ ์–ด๋”” ๋ณด๊ด€๋˜๋Š”์ง€, key๊ฐ€ ๋‹จ์ˆœ ๋ชฉ๋ก ์‹๋ณ„์ž๊ฐ€ ์•„๋‹Œ '์ปดํฌ๋„ŒํŠธ ์ฃผ๋ฏผ๋“ฑ๋ก๋ฒˆํ˜ธ'์ธ ์ด์œ ๋ฅผ React ๋ Œ๋” ํŠธ๋ฆฌ ๊ตฌ์กฐ๋กœ ํŒŒํ—ค์นฉ๋‹ˆ๋‹ค.

๐ŸŽฏ ์ด ์„น์…˜์„ ์ฝ๊ณ  ๋‚˜๋ฉด:

  • ์ƒํƒœ(State) ๊ฐ€ ์ปดํฌ๋„ŒํŠธ ํ•จ์ˆ˜ "์•ˆ"์ด ์•„๋‹ˆ๋ผ React ๊ฐ€ ๋ Œ๋” ํŠธ๋ฆฌ(Render Tree) ์˜ "์œ„์น˜"์— ์—ฐ๊ฒฐํ•ด์„œ ๋ณด๊ด€ํ•œ๋‹ค๋Š” ์‚ฌ์‹ค์„ ์„ค๋ช…ํ•  ์ˆ˜ ์žˆ์–ด์š”.
  • key ๊ฐ€ ๋‹จ์ˆœ ๋ชฉ๋ก ์‹๋ณ„์ž๊ฐ€ ์•„๋‹ˆ๋ผ, ์ปดํฌ๋„ŒํŠธ์˜ "์ฃผ๋ฏผ๋“ฑ๋ก๋ฒˆํ˜ธ"์ด์ž ์ƒํƒœ ์žฌํƒ„์ƒ ํ•ตํญํƒ„์ž„์„ ์ดํ•ดํ•  ์ˆ˜ ์žˆ์–ด์š”.
  • key ํŠธ๋ฆญ์„ ์‹ค๋ฌด์—์„œ ํผ ๊ฐ•์ œ ๋ฆฌ์…‹, ์ฑ„ํŒ…์ฐฝ ์ธ์Šคํ„ด์Šค ๋ถ„๋ฆฌ ๋“ฑ์— ๋ฐ”๋กœ ์ ์šฉํ•  ์ˆ˜ ์žˆ์–ด์š”.
  • ๋ Œ๋” ํ•จ์ˆ˜ ์•ˆ์— ์ปดํฌ๋„ŒํŠธ๋ฅผ ์ค‘์ฒฉ ์ •์˜ํ•˜๋ฉด ์™œ ์ƒํƒœ๊ฐ€ ๋งค๋ฒˆ ํญ๋ฐœํ•˜๋Š”์ง€ ์ •ํ™•ํžˆ ์ง„๋‹จํ•  ์ˆ˜ ์žˆ์–ด์š”.

๐Ÿ“‹ ๋ชฉ์ฐจ

  1. ์ด ๋ฌธ์„œ๋ฅผ ์ฝ๊ธฐ ์ „์—
  2. ์™œ ์•Œ์•„์•ผ ํ•˜๋Š”๊ฐ€: ์ƒํƒœ๊ฐ€ "์‚ฌ๋ผ์ง€๋Š”" ๋ฏธ์Šคํ„ฐ๋ฆฌ
  3. ๋น„์œ ๋กœ ๋จผ์ € ์ดํ•ดํ•˜๊ธฐ
  4. ๋ Œ๋” ํŠธ๋ฆฌ๋ž€ ๋ฌด์—‡์ธ๊ฐ€
  5. ์ƒํƒœ๋Š” ํŠธ๋ฆฌ์˜ "์œ„์น˜"์— ์‚ฐ๋‹ค
  6. ๊ฐ™์€ ์œ„์น˜, ๊ฐ™์€ ํƒ€์ž… โ†’ ์ƒํƒœ ๋ณด์กด์˜ ํ•จ์ •
  7. ๊ฐ™์€ ์œ„์น˜, ๋‹ค๋ฅธ ํƒ€์ž… โ†’ ์ƒํƒœ ์™„์ „ ๋ฆฌ์…‹
  8. key โ€” ์ปดํฌ๋„ŒํŠธ์˜ ์ฃผ๋ฏผ๋“ฑ๋ก๋ฒˆํ˜ธ
  9. key ํŠธ๋ฆญ ์‹ค๋ฌด ํŒจํ„ด
  10. ์ ˆ๋Œ€ ๊ธˆ์ง€: ๋ Œ๋” ํ•จ์ˆ˜ ์•ˆ์— ์ปดํฌ๋„ŒํŠธ ์ค‘์ฒฉ ์ •์˜
  11. ์—๋Ÿฌ ํ•ด๊ฒฐ ์นดํƒˆ๋กœ๊ทธ
  12. ์ด๋ฒˆ์— ๋ฐฐ์šด ๋‚ด์šฉ ์ด์ •๋ฆฌ
  13. ๋งˆ๋ฌด๋ฆฌ ํ€ด์ฆˆ
  14. ๋” ์•Œ์•„๋ณด๊ธฐ

๐Ÿ“Œ ์ด ๋ฌธ์„œ๋ฅผ ์ฝ๊ธฐ ์ „์—

โฑ๏ธ ์˜ˆ์ƒ ์ฝ๊ธฐ ์‹œ๊ฐ„: 15๋ถ„ (์ „์ฒด) / ํ•ต์‹ฌ ํŒŒํŠธ๋งŒ: 8๋ถ„

๐Ÿ—บ๏ธ ์ด ๋ฌธ์„œ์˜ ํ๋ฆ„

[๋ Œ๋” ํŠธ๋ฆฌ ๊ฐœ๋…] โ†’ [์ƒํƒœ ๋ณด๊ด€ ์œ„์น˜์˜ ๋น„๋ฐ€] โ†’ [ํƒ€์ž… ๋น„๊ต ์›๋ฆฌ] โ†’ [key์˜ ์ง„์งœ ์ •์ฒด] โ†’ [์‹ค๋ฌด key ํŠธ๋ฆญ] โ†’ [์น˜๋ช…์  ์•ˆํ‹ฐ ํŒจํ„ด] โ†’ [์—๋Ÿฌ ์นดํƒˆ๋กœ๊ทธ]

๐ŸŽฏ ์ด ๋ฌธ์„œ๋ฅผ ๋‹ค ์ฝ์œผ๋ฉด ํ•  ์ˆ˜ ์žˆ๋Š” ๊ฒƒ

  • "์™œ ์ปดํฌ๋„ŒํŠธ๋ฅผ ๊ต์ฒดํ–ˆ๋Š”๋ฐ ์ƒํƒœ๊ฐ€ ์œ ์ง€๋˜์ง€?" ๋ฅผ ์Šค์Šค๋กœ ์„ค๋ช…ํ•  ์ˆ˜ ์žˆ๋‹ค.
  • key ๋ฅผ ๋ชฉ๋ก ์ด์™ธ์˜ ๊ณณ์—์„œ๋„ ์ „๋žต์ ์œผ๋กœ ํ™œ์šฉํ•  ์ˆ˜ ์žˆ๋‹ค.
  • ์ฝ”๋“œ ๋ฆฌ๋ทฐ์—์„œ "๋ Œ๋” ์•ˆ์— ์ปดํฌ๋„ŒํŠธ ์ •์˜ ๊ธˆ์ง€!" ์ด์œ ๋ฅผ ์ •ํ™•ํžˆ ์„ค๋ช…ํ•  ์ˆ˜ ์žˆ๋‹ค.

๐Ÿ—บ๏ธ ์ด ๋ฌธ์„œ์˜ ๋ฐฐ๊ฒฝ ์„ธ๊ณ„๊ด€: '์˜์ˆ˜๋„ค ์ปค๋ฎค๋‹ˆํ‹ฐ'

  • ์˜์ฒ (์‹ ์ž… ํ”„๋ก ํŠธ์—”๋“œ): "์˜ํ˜ธ ๋‹˜, ์ด์ƒํ•ด์š”. ํ”Œ๋ ˆ์ด์–ด A ์—์„œ ํ”Œ๋ ˆ์ด์–ด B ๋กœ ์ „ํ™˜ํ•ด๋„ ์ ์ˆ˜๊ฐ€ ๊ทธ๋Œ€๋กœ ๋‚จ์•„์žˆ์–ด์š”. ๋ถ„๋ช…ํžˆ ๋‹ค๋ฅธ ์‚ฌ๋žŒ์ธ๋ฐ ์ƒํƒœ๊ฐ€ ๋ฆฌ์…‹์ด ์•ˆ ๋œ๋‹ค๊ณ ์š”. ์ œ๊ฐ€ ๋ฒ„๊ทธ๋ฅผ ๋งŒ๋“  ๊ฒŒ ์•„๋‹Œ๊ฐ€์š”?"
  • ์˜ํ˜ธ(๋ฆฌ๋“œ ํ”„๋ก ํŠธ์—”๋“œ): "๋ฒ„๊ทธ ์•„๋‹ˆ์—์š”, ์˜์ฒ  ๋‹˜. React ๊ฐ€ ์˜๋„์ ์œผ๋กœ ๊ทธ๋ ‡๊ฒŒ ๋™์ž‘ํ•œ ๊ฑฐ์˜ˆ์š”. ์ƒํƒœ๋Š” ์ปดํฌ๋„ŒํŠธ ํ•จ์ˆ˜ ์•ˆ์— ์‚ฌ๋Š” ๊ฒŒ ์•„๋‹ˆ๋ผ, ๋ Œ๋” ํŠธ๋ฆฌ์˜ ์œ„์น˜ ์— ์‚ฌ๋Š” ๊ฑฐ๊ฑฐ๋“ ์š”. ๊ทธ ๊ฐœ๋…์„ ์ดํ•ดํ•˜๋ฉด key ๊ฐ€ ์™œ '๋‹จ์ˆœ ์‹๋ณ„์ž'๊ฐ€ ์•„๋‹Œ '์ƒํƒœ ํญํƒ„'์ธ์ง€๋„ ๋ฐ”๋กœ ๋ณด์—ฌ์š”."
  • ์˜์ˆ˜(PM): "์ž ๊น, ๊ทธ๋Ÿผ ๋Œ“๊ธ€ ์ž‘์„ฑ ํผ๋„ ์ œ์ถœ ํ›„์— ์•ˆ ์ง€์›Œ์ง€๋Š” ๋ฌธ์ œ๋„ ๊ทธ๊ฑฐ ๋•Œ๋ฌธ์ธ๊ฐ€์š”? ๋งค๋ฒˆ ์ƒˆ๋กœ ๋งˆ์šดํŠธํ•ด์„œ ๋ฆฌ์…‹์‹œํ‚ค๋Š” ํŠธ๋ฆญ์ด ์žˆ๋‹ค๊ณ  ๋“ค์—ˆ๋Š”๋ฐ..."
  • ์˜ํ˜ธ: "๋„ค, ๋ฐ”๋กœ ๊ทธ key ํŠธ๋ฆญ์ด์—์š”. ์˜ค๋Š˜ ํ•œ ๋ฐฉ์— ์ •๋ฆฌํ•ด ๋“œ๋ฆด๊ฒŒ์š”."

๐Ÿค” ์™œ ์•Œ์•„์•ผ ํ•˜๋Š”๊ฐ€: ์ƒํƒœ๊ฐ€ "์‚ฌ๋ผ์ง€๋Š”" ๋ฏธ์Šคํ„ฐ๋ฆฌ ๐ŸŸข

๐ŸŽฏ ์ด ์„น์…˜์„ ์ฝ๊ณ  ๋‚˜๋ฉด:

  • ์‹ ์ž… ๊ฐœ๋ฐœ์ž๊ฐ€ ๊ฒช๋Š” "์ƒํƒœ๊ฐ€ ์œ ์ง€๋˜๋Š”/์‚ฌ๋ผ์ง€๋Š”" ํ˜„์ƒ์ด ์™œ ์ผ์–ด๋‚˜๋Š”์ง€ ๊ตฌ์กฐ์ ์œผ๋กœ ์ดํ•ดํ•  ์ˆ˜ ์žˆ์–ด์š”.
  • React ๊ฐ€ ์ปดํฌ๋„ŒํŠธ๋ฅผ ์–ด๋–ป๊ฒŒ "์ธ์‹"ํ•˜๋Š”์ง€ ๋‚ด๋ถ€ ์›๋ฆฌ๋ฅผ ์•Œ ์ˆ˜ ์žˆ์–ด์š”.

์˜์ˆ˜๋„ค ์ปค๋ฎค๋‹ˆํ‹ฐ์—๋Š” ์Šคํ„ฐ๋”” ์„ธ์…˜ ์ ์ˆ˜ํŒ ๊ธฐ๋Šฅ์ด ์žˆ์–ด์š”. ์˜์ฒ ์ด ์ด๋ ‡๊ฒŒ ๋งŒ๋“ค์—ˆ์Šต๋‹ˆ๋‹ค.

// โŒ ์˜์ฒ ์ด์˜ ์ดˆ๊ธฐ ๊ตฌํ˜„ โ€” ์ ์ˆ˜๊ฐ€ ์œ ์ง€๋˜๋Š” ๋ฒ„๊ทธ๋ฅผ ํ’ˆ๊ณ  ์žˆ๋‹ค
function Scoreboard() {
  const [isPlayerA, setIsPlayerA] = useState(true); // ํ˜„์žฌ ํ”Œ๋ ˆ์ด์–ด ํ† ๊ธ€ ์ƒํƒœ
 
  return (
    <div>
      {/* ๐Ÿšจ ์˜์ฒ ์ด์˜ ์˜คํ•ด: "isPlayerA๊ฐ€ ๋ฐ”๋€Œ๋ฉด ์™„์ „ํžˆ ๋‹ค๋ฅธ ์‚ฌ๋žŒ์ด๋‹ˆ๊นŒ ์ ์ˆ˜ ๋ฆฌ์…‹๋˜๊ฒ ์ง€?" */}
      {isPlayerA ? (
        <Counter person="์˜ํ˜ธ" /> // isPlayerA=true ์ผ ๋•Œ ๋ Œ๋”๋ง
      ) : (
        <Counter person="์˜์ฒ " /> // isPlayerA=false ์ผ ๋•Œ ๋ Œ๋”๋ง
      )}
      <button onClick={() => setIsPlayerA(!isPlayerA)}>
        ๋‹ค์Œ ํ”Œ๋ ˆ์ด์–ด
      </button>
    </div>
  );
}
 
function Counter({ person }) {
  const [score, setScore] = useState(0); // ๊ฐ์ž์˜ ์ ์ˆ˜
 
  return (
    <div>
      <h1>{person} ์˜ ์ ์ˆ˜: {score}</h1>
      <button onClick={() => setScore(score + 1)}>+1</button>
    </div>
  );
}

์˜์ฒ ์ด๋Š” "๋‹ค์Œ ํ”Œ๋ ˆ์ด์–ด" ๋ฒ„ํŠผ์„ ๋ˆ„๋ฅด๋ฉด ์˜ํ˜ธ์˜ ์ ์ˆ˜ 5์ ์ด ์‚ฌ๋ผ์ง€๊ณ  ์˜์ฒ ์˜ ์ ์ˆ˜๊ฐ€ 0์ ์—์„œ ์‹œ์ž‘๋  ๊ฑฐ๋ผ ๊ธฐ๋Œ€ํ–ˆ์–ด์š”. ํ•˜์ง€๋งŒ ์‹ค์ œ๋กœ ๋ˆŒ๋Ÿฌ๋ณด๋ฉด ์ ์ˆ˜๊ฐ€ ๊ทธ๋Œ€๋กœ ๋‚จ์•„์žˆ์Šต๋‹ˆ๋‹ค. ์ด๊ฒŒ ๋ฐ”๋กœ React ๋ Œ๋” ํŠธ๋ฆฌ ์ดํ•ด๊ฐ€ ์—†์œผ๋ฉด ์ ˆ๋Œ€ ์˜ˆ์ธกํ•  ์ˆ˜ ์—†๋Š” ๋™์ž‘์ด์—์š”.

์™œ ์ด๋Ÿฐ ์ผ์ด ๋ฒŒ์–ด์งˆ๊นŒ์š”? ํ•ต์‹ฌ์€ ๋ฐ”๋กœ ์ด๊ฑฐ์˜ˆ์š”:

React ๋Š” ์ปดํฌ๋„ŒํŠธ ์ธ์Šคํ„ด์Šค(instance) ๋ฅผ "JSX ๋ฅผ ๋ฐ˜ํ™˜ํ•œ ํ•จ์ˆ˜"๊ฐ€ ์•„๋‹ˆ๋ผ, "๋ Œ๋” ํŠธ๋ฆฌ์—์„œ์˜ ์œ„์น˜(position)"๋กœ ์‹๋ณ„ํ•ด์š”.

๊ฐ™์€ <div> ์˜ ์ฒซ ๋ฒˆ์งธ ์ž์‹ ์œ„์น˜์— ๊ณ„์†ํ•ด์„œ Counter ํƒ€์ž…์ด ์žˆ๋‹ค๋ฉด, React ๋Š” "์•„ ์ด ์ž๋ฆฌ์— ์žˆ๋Š” Counter ๋Š” ๋™์ผํ•œ ๋…€์„์ด๊ตฌ๋‚˜" ๋ผ๊ณ  ํŒ๋‹จํ•˜๊ณ  ์ƒํƒœ๋ฅผ ์œ ์ง€์‹œ์ผœ์š”. person prop ์ด "์˜ํ˜ธ" ์—์„œ "์˜์ฒ " ๋กœ ๋ฐ”๋€Œ์–ด๋„์š”.

์ด ๋™์ž‘์„ ์ดํ•ดํ•˜์ง€ ๋ชปํ•˜๋ฉด:

  1. ์˜ˆ์ƒ์น˜ ๋ชปํ•œ ์ƒํƒœ ์œ ์ง€ โ€” ์˜๋„์ ์œผ๋กœ ๋ฆฌ์…‹ํ•ด์•ผ ํ•  ์ƒํƒœ๊ฐ€ ์‚ด์•„๋‚จ์•„์š”.
  2. ์˜ˆ์ƒ์น˜ ๋ชปํ•œ ์ƒํƒœ ๋ฆฌ์…‹ โ€” ๋ฉ€์ฉกํžˆ ์ž…๋ ฅ ์ค‘์ธ ํผ์ด ๊ฐ‘์ž๊ธฐ ์ดˆ๊ธฐํ™”๋ผ์š”.
  3. ์ค‘์ฒฉ ์ปดํฌ๋„ŒํŠธ ์ •์˜ ์ง€๋ขฐ โ€” ์„ฑ๋Šฅ ์ตœ์ ํ™”ํ•˜๋ ค๋‹ค ์˜คํžˆ๋ ค ๋ชจ๋“  ์ƒํƒœ๊ฐ€ ๋งค๋ฒˆ ํญ๋ฐœํ•ด์š”.

๐Ÿ—๏ธ ๋น„์œ ๋กœ ๋จผ์ € ์ดํ•ดํ•˜๊ธฐ

๐Ÿง’ 5์‚ด์—๊ฒŒ ์„ค๋ช…ํ•œ๋‹ค๋ฉด?

์นดํŽ˜์— ํ…Œ์ด๋ธ”์ด 10๊ฐœ ์žˆ์–ด์š”. ์†๋‹˜์ด ์•‰์œผ๋ฉด ๊ทธ ํ…Œ์ด๋ธ” ๋ฒˆํ˜ธ๋กœ ๊ธฐ์–ตํ•˜๋Š” ๊ฑฐ์˜ˆ์š”.
1๋ฒˆ ํ…Œ์ด๋ธ”์— ํ• ๋จธ๋‹ˆ๊ฐ€ ์•‰์•˜๋‹ค๊ฐ€ ๋‚˜๊ฐ€๊ณ , ๊ทธ ์ž๋ฆฌ์— ํ• ์•„๋ฒ„์ง€๊ฐ€ ์•‰์œผ๋ฉด
์นดํŽ˜ ์•Œ๋ฐ”์ƒ(React) ์€ "1๋ฒˆ ํ…Œ์ด๋ธ” ์†๋‹˜" ์ด๋ผ๊ณ ๋งŒ ๊ธฐ์–ตํ•ด์š”.
๊ทธ๋ž˜์„œ ํ• ๋จธ๋‹ˆ๊ฐ€ ์‹œํ‚จ ์•„๋ฉ”๋ฆฌ์นด๋…ธ(์ƒํƒœ) ๊ฐ€ ์•„์ง๋„ 1๋ฒˆ ํ…Œ์ด๋ธ” ์œ„์— ์žˆ๋Š” ๊ฒƒ์ฒ˜๋Ÿผ ์ทจ๊ธ‰ํ•ด์š”.

ํ•˜์ง€๋งŒ ํ…Œ์ด๋ธ” ๋ฒˆํ˜ธํŒ(key) ์„ ๊ฐˆ์•„๋ผ์šฐ๋ฉด? "์•„, ์ด๊ฑด ์™„์ „ํžˆ ๋‹ค๋ฅธ ํ…Œ์ด๋ธ”์ด๋„ค!" ํ•˜๊ณ 
์ฒ˜์Œ๋ถ€ํ„ฐ ์ƒˆ๋กœ ์ฃผ๋ฌธ์„ ๋ฐ›์•„์š”. ์•„๋ฉ”๋ฆฌ์นด๋…ธ(์ƒํƒœ) ๋Š” ์‚ฌ๋ผ์ง€๊ณ  ๊นจ๋—ํ•œ ํ…Œ์ด๋ธ”์ด ๋˜๋Š” ๊ฑฐ์ฃ .

React ์˜ ๋ Œ๋” ํŠธ๋ฆฌ๋Š” ์ž๋ฆฌ ๋ฐฐ์น˜๋„(์ขŒ์„ํ‘œ) ์˜ˆ์š”. ์ƒํƒœ๋Š” ๊ทธ ์ž๋ฆฌ์— ๋ถ™์–ด์žˆ๋Š” ํฌ์ŠคํŠธ์ž‡์ด๊ณ ์š”. ์ž๋ฆฌ์— ์•‰๋Š” ์‚ฌ๋žŒ(์ปดํฌ๋„ŒํŠธ ์ธ์Šคํ„ด์Šค) ์ด ๋ฐ”๋€Œ์–ด๋„, ๊ฐ™์€ ์ž๋ฆฌ์— ๊ฐ™์€ ์ข…๋ฅ˜์˜ ์˜์ž(์ปดํฌ๋„ŒํŠธ ํƒ€์ž…) ๊ฐ€ ์žˆ์œผ๋ฉด ํฌ์ŠคํŠธ์ž‡์€ ๊ทธ๋Œ€๋กœ์˜ˆ์š”.

key ๋Š” ์ž๋ฆฌ ๋ฒˆํ˜ธํŒ์„ ์•„์˜ˆ ์ƒˆ ๋ฒˆํ˜ธํŒ์œผ๋กœ ๊ต์ฒดํ•˜๋Š” ๊ฑฐ์˜ˆ์š”. ๋ฒˆํ˜ธ๊ฐ€ ๋ฐ”๋€Œ๋ฉด React ๋Š” ์™„์ „ํžˆ ์ƒˆ ์ž๋ฆฌ๋กœ ์ธ์‹ํ•ด์„œ, ๊ธฐ์กด ํฌ์ŠคํŠธ์ž‡(์ƒํƒœ) ์„ ๋ชจ๋‘ ๋–ผ์–ด๋‚ด๊ณ  ์ƒˆ ํฌ์ŠคํŠธ์ž‡(์ดˆ๊ธฐ ์ƒํƒœ) ์„ ๋ถ™์—ฌ์š”.


๐Ÿงฉ ๋ Œ๋” ํŠธ๋ฆฌ๋ž€ ๋ฌด์—‡์ธ๊ฐ€ ๐ŸŸข

๐ŸŽฏ ์ด ์„น์…˜์„ ์ฝ๊ณ  ๋‚˜๋ฉด:

  • React ๊ฐ€ JSX ๋ฅผ ์–ด๋–ป๊ฒŒ ํŠธ๋ฆฌ ๊ตฌ์กฐ๋กœ ํ•ด์„ํ•˜๋Š”์ง€ ์„ค๋ช…ํ•  ์ˆ˜ ์žˆ์–ด์š”.
  • "๋ Œ๋” ํŠธ๋ฆฌ์—์„œ์˜ ์œ„์น˜" ๊ฐ€ ๋ฌด์—‡์„ ์˜๋ฏธํ•˜๋Š”์ง€ ์•Œ ์ˆ˜ ์žˆ์–ด์š”.

๐Ÿค” ์ž ๊น, ๋จผ์ € ์ƒ๊ฐํ•ด๋ด
<div> ์•ˆ์— <Counter /> ๊ฐ€ ํ•˜๋‚˜ ์žˆ์–ด์š”. ์กฐ๊ฑด๋ถ€ ๋ Œ๋”๋ง์œผ๋กœ ์ด <Counter /> ๋ฅผ ์ˆจ๊ฒผ๋‹ค๊ฐ€ ๋‹ค์‹œ ๋ณด์—ฌ์ฃผ๋ฉด, ์ƒํƒœ๋Š” ์‚ด์•„์žˆ์„๊นŒ์š” ์•„๋‹ˆ๋ฉด ๋ฆฌ์…‹๋ ๊นŒ์š”?
์ง๊ฐ์ ์œผ๋กœ ์˜ˆ์ธกํ•ด๋ณด๊ณ  ์•„๋ž˜๋กœ ๋‚ด๋ ค๊ฐ€์š”.

React ๊ฐ€ ์ปดํฌ๋„ŒํŠธ๋ฅผ ๋ Œ๋”๋งํ•  ๋•Œ, ๋‚ด๋ถ€์ ์œผ๋กœ UI ํŠธ๋ฆฌ(UI Tree) ๋ฅผ ๊ตฌ์„ฑํ•ด์š”. ์ด ํŠธ๋ฆฌ๋Š” ์šฐ๋ฆฌ๊ฐ€ ์ž‘์„ฑํ•œ JSX ๊ตฌ์กฐ๋ฅผ ๊ทธ๋Œ€๋กœ ๋ฐ˜์˜ํ•ด์š”.

// ์•„๋ž˜ JSX๋Š”...
<App>
  <Scoreboard>
    <Counter person="์˜ํ˜ธ" />
  </Scoreboard>
</App>

// React ๋‚ด๋ถ€์—์„œ๋Š” ์ด๋Ÿฐ ํŠธ๋ฆฌ๋กœ ๊ด€๋ฆฌ๋ผ์š”:
App
โ””โ”€โ”€ Scoreboard
    โ””โ”€โ”€ Counter (position: 0๋ฒˆ์งธ ์ž์‹)

์ค‘์š”ํ•œ ๊ฑด React ๊ฐ€ ๊ฐ ์ปดํฌ๋„ŒํŠธ๋ฅผ ํŠธ๋ฆฌ์—์„œ์˜ ์œ„์น˜๋กœ ์‹๋ณ„ํ•œ๋‹ค๋Š” ๊ฑฐ์˜ˆ์š”. "Counter ๋ผ๋Š” ์ด๋ฆ„์˜ ํ•จ์ˆ˜" ๊ฐ€ ์•„๋‹ˆ๋ผ, "Scoreboard ์˜ 0๋ฒˆ์งธ ์ž์‹" ์ด๋ผ๋Š” ์ขŒํ‘œ๋กœ์š”.

// โœ… ๋ Œ๋” ํŠธ๋ฆฌ ์œ„์น˜ ๊ฐœ๋…์„ ์ฝ”๋“œ๋กœ ํ‘œํ˜„ํ•˜๋ฉด
function Scoreboard() {
  return (
    <div>
      {/* ์œ„์น˜ 0: ์—ฌ๊ธฐ์— ๋ฌด์—‡์ด ์˜ค๋“  React๋Š” "div์˜ ์ฒซ ๋ฒˆ์งธ ์ž์‹"์œผ๋กœ ์ธ์‹ */}
      <Counter person="์˜ํ˜ธ" />
 
      {/* ์œ„์น˜ 1: div์˜ ๋‘ ๋ฒˆ์งธ ์ž์‹ */}
      <Counter person="์˜์ฒ " />
    </div>
  );
}

์œ„ ์˜ˆ์‹œ์—์„œ ๋‘ <Counter /> ๋Š” ๋‹ค๋ฅธ ์œ„์น˜์— ์žˆ์–ด์š”. ๊ทธ๋ž˜์„œ React ๋Š” ์ด ๋‘˜์„ ์™„์ „ํžˆ ๋ณ„๊ฐœ์˜ ์ธ์Šคํ„ด์Šค๋กœ ๊ด€๋ฆฌํ•˜๊ณ , ๊ฐ์ž ๋…๋ฆฝ์ ์ธ ์ƒํƒœ๋ฅผ ๊ฐ€์ ธ์š”.

๐Ÿ”— ์—ฐ๊ฒฐ ๊ณ ๋ฆฌ
React ์˜ ์žฌ์กฐ์ •(Reconciliation) ์•Œ๊ณ ๋ฆฌ์ฆ˜์ด ๋ฐ”๋กœ ์ด ํŠธ๋ฆฌ ๋น„๊ต๋ฅผ ๋‹ด๋‹นํ•ด์š”. "๊ฐ™์€ ์œ„์น˜์— ๊ฐ™์€ ํƒ€์ž…์ด๋ฉด ์—…๋ฐ์ดํŠธ, ๋‹ค๋ฅธ ํƒ€์ž…์ด๋ฉด ์ œ๊ฑฐ ํ›„ ์ƒˆ๋กœ ๋งˆ์šดํŠธ" ๋ผ๋Š” ๋‹จ์ˆœํ•œ ๊ทœ์น™์ด ๋ชจ๋“  ๊ฑธ ์ง€๋ฐฐํ•ด์š”.

๐Ÿ’ก ํ•œ ์ค„๋กœ ๊ธฐ์–ตํ•˜๊ธฐ
React ์—๊ฒŒ ์ปดํฌ๋„ŒํŠธ์˜ ์ •์ฒด์„ฑ์€ "์ด๋ฆ„"์ด ์•„๋‹ˆ๋ผ "๋ Œ๋” ํŠธ๋ฆฌ์—์„œ์˜ ์ขŒ์„ ๋ฒˆํ˜ธ"์˜ˆ์š”.


๐Ÿงฉ ์ƒํƒœ๋Š” ํŠธ๋ฆฌ์˜ "์œ„์น˜"์— ์‚ฐ๋‹ค ๐ŸŸข

๐ŸŽฏ ์ด ์„น์…˜์„ ์ฝ๊ณ  ๋‚˜๋ฉด:

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

๐Ÿค” ์ž ๊น, ๋จผ์ € ์ƒ๊ฐํ•ด๋ด
const [count, setCount] = useState(0) ์ด ์ฝ”๋“œ์—์„œ count ๋Š” ์–ด๋””์— ์ €์žฅ๋ ๊นŒ์š”?
"์ปดํฌ๋„ŒํŠธ ํ•จ์ˆ˜ ๋‚ด๋ถ€์— ์ €์žฅ๋˜๊ฒ ์ง€" ๊ฐ€ ์ง๊ฐ์ด๋ผ๋ฉด, ์•„๋ž˜๋ฅผ ์ฝ์œผ๋ฉด ์„ธ๊ณ„๊ด€์ด ๋’ค์ง‘ํž ๊ฑฐ์˜ˆ์š”.

React ์˜ ํ•ต์‹ฌ ์„ค๊ณ„ ์›์น™ ์ค‘ ํ•˜๋‚˜๋Š”, ์ƒํƒœ๋Š” ์ปดํฌ๋„ŒํŠธ ํ•จ์ˆ˜ ๋ฐ”๊นฅ์— ์žˆ๋‹ค ๋Š” ๊ฑฐ์˜ˆ์š”. ์ข€ ๋” ์ •ํ™•ํžˆ ๋งํ•˜๋ฉด, React ๋Ÿฐํƒ€์ž„์ด ๊ด€๋ฆฌํ•˜๋Š” ๋ณ„๋„์˜ ์ €์žฅ์†Œ(fiber tree ๋˜๋Š” ๋‚ด๋ถ€ ๋ฉ”๋ชจ๋ฆฌ) ์— ํŠธ๋ฆฌ ์œ„์น˜๋ณ„๋กœ ์—ฐ๊ฒฐ๋˜์–ด ๋ณด๊ด€๋ผ์š”.

// ๐Ÿงช ์‹คํ—˜: ๊ฐ™์€ ์ปดํฌ๋„ŒํŠธ๋ฅผ ๋‘ ๊ณณ์—์„œ ๋ Œ๋”๋ง
function App() {
  return (
    <div>
      {/* ์ด ๋‘˜์€ ๊ฐ™์€ Counter ํ•จ์ˆ˜๋ฅผ ์‚ฌ์šฉํ•˜์ง€๋งŒ... */}
      <Counter /> {/* ์œ„์น˜ A: ์ž์ฒด์ ์ธ ์ƒํƒœ๋ฅผ ๊ฐ€์ง */}
      <Counter /> {/* ์œ„์น˜ B: ์œ„์น˜ A์™€ ์™„์ „ํžˆ ๋…๋ฆฝ์ ์ธ ์ƒํƒœ๋ฅผ ๊ฐ€์ง */}
    </div>
  );
}

์œ„ ์ฝ”๋“œ์—์„œ ์™ผ์ชฝ Counter ๋ฅผ 5๋ฒˆ ํด๋ฆญํ•˜๋ฉด ์˜ค๋ฅธ์ชฝ Counter ์—๋Š” ์˜ํ–ฅ์ด ์—†์–ด์š”. ์ด๊ฑด ๋‹น์—ฐํ•ด ๋ณด์ด์ง€๋งŒ, ๊ทธ ์ด์œ ๋ฅผ ์ œ๋Œ€๋กœ ์ดํ•ดํ•˜๋Š” ์‚ฌ๋žŒ์€ ๋“œ๋ฌผ์–ด์š”.

์ƒํƒœ๊ฐ€ ํ•จ์ˆ˜ ์•ˆ์— ์žˆ๋‹ค๋ฉด Counter ํ•จ์ˆ˜๋Š” ๋‘ ๋ฒˆ ํ˜ธ์ถœ๋  ๋•Œ๋งˆ๋‹ค ๊ฐ™์€ ์ดˆ๊ธฐ๊ฐ’ 0 ์—์„œ ์‹œ์ž‘ํ•  ํ…Œ๊ณ , ํด๋ฆญํ•ด๋„ React ๋Š” "์–ด๋–ค Counter ์˜ ์ƒํƒœ๋ฅผ ๋ฐ”๊ฟ”์•ผ ํ•˜์ง€?" ๋ฅผ ๋ชจ๋ฅผ ๊ฑฐ์˜ˆ์š”. ํ•˜์ง€๋งŒ ์‹ค์ œ๋กœ๋Š” React ๊ฐ€ ํŠธ๋ฆฌ ์œ„์น˜ A, B ๊ฐ๊ฐ์— ์ƒํƒœ ์Šฌ๋กฏ์„ ๋”ฐ๋กœ ๋งŒ๋“ค์–ด ๊ด€๋ฆฌํ•˜๊ธฐ ๋•Œ๋ฌธ์— ๋…๋ฆฝ์ ์œผ๋กœ ์ž‘๋™ํ•ด์š”.

// ๐Ÿ’ก React ๋‚ด๋ถ€ ๊ฐœ๋… (์˜์‚ฌ ์ฝ”๋“œ, ์‹ค์ œ ๊ตฌํ˜„๊ณผ ๋‹ค๋ฅผ ์ˆ˜ ์žˆ์Œ)
const internalStateStore = {
  "App > div > Counter[0]": { count: 5 },  // ์œ„์น˜ A
  "App > div > Counter[1]": { count: 0 },  // ์œ„์น˜ B
};
// Counter ํ•จ์ˆ˜๊ฐ€ ์‹คํ–‰๋  ๋•Œ useState(0)๋Š”
// ํ˜„์žฌ ๋ Œ๋”๋ง ์ค‘์ธ ์œ„์น˜์˜ ์Šฌ๋กฏ์„ ์ฐพ์•„์„œ ๊ฐ’์„ ๋ฐ˜ํ™˜ํ•ด์š”

์ด ์‚ฌ์‹ค์—์„œ ์ค‘์š”ํ•œ ๊ฒฐ๋ก ์ด ๋‚˜์™€์š”:

์ปดํฌ๋„ŒํŠธ๊ฐ€ unmount(ํŠธ๋ฆฌ์—์„œ ์ œ๊ฑฐ) ๋˜๋ฉด, ๊ทธ ์œ„์น˜์— ์—ฐ๊ฒฐ๋œ ์ƒํƒœ ์Šฌ๋กฏ๋„ ํ•จ๊ป˜ ์‚ญ์ œ๋ผ์š”.

// ๐Ÿงช ์กฐ๊ฑด๋ถ€ ๋ Œ๋”๋ง ์‹คํ—˜
function App() {
  const [showCounter, setShowCounter] = useState(true);
 
  return (
    <div>
      {showCounter && <Counter />} {/* true๋ฉด ๋งˆ์šดํŠธ, false๋ฉด ์–ธ๋งˆ์šดํŠธ */}
      <button onClick={() => setShowCounter(!showCounter)}>
        ํ† ๊ธ€
      </button>
    </div>
  );
}

showCounter ๋ฅผ false ๋กœ ๋ฐ”๊พธ๋ฉด Counter ๊ฐ€ ํŠธ๋ฆฌ์—์„œ ์ œ๊ฑฐ๋ผ์š”. ์ƒํƒœ๋„ ํ•จ๊ป˜ ๋‚ ์•„๊ฐ€์š”. ๋‹ค์‹œ true ๋กœ ๋ฐ”๊พธ๋ฉด Counter ๊ฐ€ ์ƒˆ๋กœ ๋งˆ์šดํŠธ๋˜๊ณ  ์ƒํƒœ๋Š” ์ดˆ๊ธฐ๊ฐ’ 0 ์—์„œ ๋‹ค์‹œ ์‹œ์ž‘ํ•ด์š”.

๐Ÿ’ก ํ•œ ์ค„๋กœ ๊ธฐ์–ตํ•˜๊ธฐ
์ƒํƒœ๋Š” ํ•จ์ˆ˜ ์•ˆ์ด ์•„๋‹ˆ๋ผ React ๊ฐ€ ๋งŒ๋“  ์™ธ๋ถ€ ์ฃผ์†Œ๋ก์— ์žˆ๊ณ , ์ฃผ์†Œ๋Š” ํŠธ๋ฆฌ ์œ„์น˜์˜ˆ์š”. ์ฃผ์†Œ๊ฐ€ ์‚ฌ๋ผ์ง€๋ฉด(์–ธ๋งˆ์šดํŠธ) ์ƒํƒœ๋„ ์‚ฌ๋ผ์ ธ์š”.


๐Ÿงฉ ๊ฐ™์€ ์œ„์น˜, ๊ฐ™์€ ํƒ€์ž… โ†’ ์ƒํƒœ ๋ณด์กด์˜ ํ•จ์ • ๐ŸŸก

๐ŸŽฏ ์ด ์„น์…˜์„ ์ฝ๊ณ  ๋‚˜๋ฉด:

  • "๊ฐ™์€ ์œ„์น˜์— ๊ฐ™์€ ์ปดํฌ๋„ŒํŠธ ํƒ€์ž…" ์ด๋ผ๋ฉด prop ์ด ๋‹ฌ๋ผ์ ธ๋„ ์ƒํƒœ๊ฐ€ ์œ ์ง€๋˜๋Š” ์ด์œ ๋ฅผ ์„ค๋ช…ํ•  ์ˆ˜ ์žˆ์–ด์š”.
  • ์˜์ฒ ์ด์˜ ์ ์ˆ˜ํŒ ๋ฒ„๊ทธ๊ฐ€ ์™œ ๋ฐœ์ƒํ–ˆ๋Š”์ง€ ์ •ํ™•ํžˆ ์ง„๋‹จํ•  ์ˆ˜ ์žˆ์–ด์š”.

๐Ÿค” ์ž ๊น, ๋จผ์ € ์ƒ๊ฐํ•ด๋ด
isPlayerA ๊ฐ€ true ์ผ ๋•Œ <Counter person="์˜ํ˜ธ" /> ๋ฅผ, false ์ผ ๋•Œ <Counter person="์˜์ฒ " /> ๋ฅผ ๋ Œ๋”๋งํ•ด์š”.
"person" prop ์ด ๋‹ค๋ฅด๋‹ˆ๊นŒ React ๊ฐ€ ๋‹ค๋ฅธ ์ปดํฌ๋„ŒํŠธ๋กœ ์ธ์‹ํ• ๊นŒ์š”?

React ์˜ ์žฌ์กฐ์ •(Reconciliation, '์žฌ์กฐ์ •' ์€ ์ด์ „ ๊ฐ€์ƒ DOM ํŠธ๋ฆฌ์™€ ์ƒˆ ๊ฐ€์ƒ DOM ํŠธ๋ฆฌ๋ฅผ ๋น„๊ตํ•ด์„œ ์ตœ์†Œํ•œ์˜ ๋ณ€๊ฒฝ๋งŒ ์‹ค์ œ DOM ์— ๋ฐ˜์˜ํ•˜๋Š” ๊ณผ์ •์ด์—์š”) ๊ทœ์น™์€ ๋‹จ์ˆœํ•ด์š”:

๊ฐ™์€ ์œ„์น˜์— ๊ฐ™์€ ํƒ€์ž…์ด๋ฉด โ†’ ๊ธฐ์กด ์ธ์Šคํ„ด์Šค๋ฅผ ์žฌ์‚ฌ์šฉํ•˜๊ณ  prop ๋งŒ ์—…๋ฐ์ดํŠธํ•ด์š”.

// ๐Ÿ”ด ์ƒํƒœ ๋ณด์กด ํ•จ์ • โ€” ์˜์ฒ ์ด์˜ Scoreboard ๋ฒ„๊ทธ ์žฌํ˜„
function Scoreboard() {
  const [isPlayerA, setIsPlayerA] = useState(true);
 
  return (
    <div>
      {/*
        React ๊ฐ€ ๋ณด๋Š” ๊ฒƒ: "div์˜ ์ฒซ ๋ฒˆ์งธ ์ž์‹ = Counter ํƒ€์ž…"
        isPlayerA๊ฐ€ true โ†’ false ๋กœ ๋ฐ”๋€” ๋•Œ:
        - ์ด์ „ ํŠธ๋ฆฌ: Counter (person="์˜ํ˜ธ")
        - ์ƒˆ ํŠธ๋ฆฌ:   Counter (person="์˜์ฒ ")
        - React ํŒ๋‹จ: "๊ฐ™์€ ์œ„์น˜, ๊ฐ™์€ ํƒ€์ž…(Counter) โ†’ ๊ธฐ์กด ์ธ์Šคํ„ด์Šค ์œ ์ง€, prop๋งŒ ๋ณ€๊ฒฝ!"
        - ๊ฒฐ๊ณผ: score ์ƒํƒœ๊ฐ€ ์œ ์ง€๋จ ๐Ÿ˜ฑ
      */}
      {isPlayerA ? <Counter person="์˜ํ˜ธ" /> : <Counter person="์˜์ฒ " />}
      <button onClick={() => setIsPlayerA(!isPlayerA)}>๋‹ค์Œ ํ”Œ๋ ˆ์ด์–ด</button>
    </div>
  );
}

React ๋Š” prop ์˜ ๋‚ด์šฉ์ด ๋‹ฌ๋ผ๋„ ํƒ€์ž…์ด ๊ฐ™์œผ๋ฉด "๊ฐ™์€ ์ปดํฌ๋„ŒํŠธ์˜ ์ƒํƒœ๋ฅผ ์—…๋ฐ์ดํŠธํ•˜๋ฉด ๋œ๋‹ค" ๊ณ  ํŒ๋‹จํ•ด์š”. person ์ด "์˜ํ˜ธ" ์—์„œ "์˜์ฒ " ๋กœ ๋ฐ”๋€Œ์–ด๋„, ๊ทธ๊ฑด ๊ทธ๋ƒฅ ์—…๋ฐ์ดํŠธ์ผ ๋ฟ์ด์—์š”.

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

์•„๋ž˜ ๋‹ค์ด์–ด๊ทธ๋žจ์œผ๋กœ ์ •๋ฆฌํ•ด ๋ณผ๊ฒŒ์š”:

isPlayerA = true ์ผ ๋•Œ์˜ ํŠธ๋ฆฌ:
Scoreboard
โ””โ”€โ”€ div
    โ””โ”€โ”€ Counter (score=5, person="์˜ํ˜ธ")  โ† ์œ„์น˜ 0

isPlayerA = false ๋กœ ๋ณ€๊ฒฝ ํ›„ ํŠธ๋ฆฌ:
Scoreboard
โ””โ”€โ”€ div
    โ””โ”€โ”€ Counter (score=5, person="์˜์ฒ ")  โ† ์œ„์น˜ 0, ๊ฐ™์€ ์œ„์น˜!
    // score ์ƒํƒœ๊ฐ€ ๊ทธ๋Œ€๋กœ ๋‚จ์•„์žˆ๋‹ค

โžก๏ธ ๋‹ค์Œ ์„น์…˜์—์„œ๋Š”: ๋‹ค๋ฅธ ํƒ€์ž…์„ ๊ฐ™์€ ์œ„์น˜์— ๋†“์œผ๋ฉด ์ƒํƒœ๊ฐ€ ์–ด๋–ป๊ฒŒ ๋˜๋Š”์ง€ ๋ณผ๊ฒŒ์š”. ๊ทธ ์›๋ฆฌ๋ฅผ ์ดํ•ดํ•˜๋ฉด key ๊ฐ€ ์™œ "์ƒํƒœ ํญํƒ„" ์ธ์ง€๊ฐ€ ๋ฐ”๋กœ ์—ฐ๊ฒฐ๋ผ์š”.

๐Ÿ’ก ํ•œ ์ค„๋กœ ๊ธฐ์–ตํ•˜๊ธฐ
React ๋Š” prop ๋‚ด์šฉ์ด ์•„๋‹ˆ๋ผ ์ปดํฌ๋„ŒํŠธ ํƒ€์ž… ๊ณผ ํŠธ๋ฆฌ ์œ„์น˜ ๋ฅผ ๋ณด๊ณ  "๊ฐ™์€ ๋†ˆ์ด๋ƒ ๋‹ค๋ฅธ ๋†ˆ์ด๋ƒ" ๋ฅผ ํŒ๋‹จํ•ด์š”. ํƒ€์ž…๊ณผ ์œ„์น˜๊ฐ€ ๊ฐ™์œผ๋ฉด ์ƒํƒœ๋Š” ์ ˆ๋Œ€ ๋ฆฌ์…‹๋˜์ง€ ์•Š์•„์š”.


๐Ÿงฉ ๊ฐ™์€ ์œ„์น˜, ๋‹ค๋ฅธ ํƒ€์ž… โ†’ ์ƒํƒœ ์™„์ „ ๋ฆฌ์…‹ ๐ŸŸก

๐ŸŽฏ ์ด ์„น์…˜์„ ์ฝ๊ณ  ๋‚˜๋ฉด:

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

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

// โœ… ๋‹ค๋ฅธ ํƒ€์ž…์œผ๋กœ ๊ต์ฒด โ†’ ์ƒํƒœ ์™„์ „ ๋ฆฌ์…‹ ํ™•์ธ
function App() {
  const [showCounter, setShowCounter] = useState(true);
 
  return (
    <div>
      {showCounter ? (
        <Counter />   // Counter ํƒ€์ž… โ€” ์œ„์น˜ 0
      ) : (
        <p>์ ์ˆ˜๋ฅผ ๋ณด๋ ค๋ฉด ๋ฒ„ํŠผ์„ ๋ˆ„๋ฅด์„ธ์š”</p>  // p ํƒ€์ž… โ€” ์œ„์น˜ 0
      )}
      {/*
        Counter โ†’ p ๋กœ ๋ฐ”๋€” ๋•Œ:
        React ํŒ๋‹จ: "์œ„์น˜ 0์˜ ํƒ€์ž…์ด Counter์—์„œ p๋กœ ๋‹ฌ๋ผ์กŒ๋‹ค!"
        ๋™์ž‘: Counter ์–ธ๋งˆ์šดํŠธ (์ƒํƒœ ํŒŒ๊ดด) โ†’ p ์ƒˆ๋กœ ๋งˆ์šดํŠธ
      */}
      <button onClick={() => setShowCounter(!showCounter)}>ํ† ๊ธ€</button>
    </div>
  );
}

์ด ๋™์ž‘์„ ์ด์šฉํ•ด์„œ ์˜๋„์ ์œผ๋กœ ์ƒํƒœ๋ฅผ ๋ฆฌ์…‹ ํ•˜๋ ค๋Š” ์‹œ๋„๋„ ๋ณผ ์ˆ˜ ์žˆ์–ด์š”:

// โŒ ์ˆœ์ง„ํ•œ ํ•ด๊ฒฐ์ฑ… โ€” ๋‹ค๋ฅธ ์ปดํฌ๋„ŒํŠธ ๋ž˜ํผ๋กœ ๊ฐ์‹ธ๊ธฐ
// (์ด ๋ฐฉ๋ฒ•์€ ๋™์ž‘ํ•˜์ง€๋งŒ ์ฝ”๋“œ๊ฐ€ ์ง€์ €๋ถ„ํ•ด์š”)
function Scoreboard() {
  const [isPlayerA, setIsPlayerA] = useState(true);
 
  return (
    <div>
      {isPlayerA ? (
        <div>  {/* div๋กœ ๊ฐ์‹ธ์„œ "๋‹ค๋ฅธ ํƒ€์ž…"์ฒ˜๋Ÿผ ๋ณด์ด๊ฒŒ ํ•˜๋ ค๋Š” ์‹œ๋„ */}
          <Counter person="์˜ํ˜ธ" />
        </div>
      ) : (
        <section>  {/* section์€ div์™€ ๋‹ค๋ฅธ ํƒ€์ž… */}
          <Counter person="์˜์ฒ " />
        </section>
      )}
      {/*
        div์™€ section์€ ๋‹ค๋ฅธ ํƒ€์ž…์ด๋‹ˆ๊นŒ ํƒ€์ž… ๋ถˆ์ผ์น˜ โ†’ ์ƒํƒœ ๋ฆฌ์…‹
        ํ•˜์ง€๋งŒ ์ด๊ฑด ์˜๋ฏธ ์—†๋Š” ๋ž˜ํผ๋ฅผ ์ถ”๊ฐ€ํ•˜๋Š” ์ง€์ €๋ถ„ํ•œ ๋ฐฉ์‹์ด์—์š”
      */}
    </div>
  );
}

์œ„ ๋ฐฉ์‹์€ ์ž‘๋™ํ•˜๊ธด ํ•˜์ง€๋งŒ ์˜ฌ๋ฐ”๋ฅธ ํ•ด๊ฒฐ์ฑ…์ด ์•„๋‹ˆ์—์š”. ์˜ฌ๋ฐ”๋ฅธ ํ•ด๊ฒฐ์ฑ…์€ key ์˜ˆ์š”. ์ด์–ด์„œ ๋ฐ”๋กœ ์•Œ์•„๋ด์š”.

๐Ÿ’ก ํ•œ ์ค„๋กœ ๊ธฐ์–ตํ•˜๊ธฐ
ํƒ€์ž…์ด ๋‹ฌ๋ผ์ง€๋ฉด React ๋Š” ๋ฌป์ง€๋„ ๋”ฐ์ง€์ง€๋„ ์•Š๊ณ  ๊ธฐ์กด ํŠธ๋ฆฌ๋ฅผ ํ†ต์งธ๋กœ ๋ฒ„๋ฆฌ๊ณ  ์ƒˆ๋กœ ๋งŒ๋“ค์–ด์š”. ์ƒํƒœ๋Š” ํ•จ๊ป˜ ์ฆ๋ฐœํ•ด์š”.


๐Ÿงฉ key โ€” ์ปดํฌ๋„ŒํŠธ์˜ ์ฃผ๋ฏผ๋“ฑ๋ก๋ฒˆํ˜ธ ๐ŸŸก

๐ŸŽฏ ์ด ์„น์…˜์„ ์ฝ๊ณ  ๋‚˜๋ฉด:

  • key ๊ฐ€ ๋ชฉ๋ก ๋ Œ๋”๋ง๋ฟ ์•„๋‹ˆ๋ผ ์ปดํฌ๋„ŒํŠธ ์ธ์Šคํ„ด์Šค์˜ "์‹ ์› ์ฆ๋ช…์„œ" ์—ญํ• ์„ ํ•œ๋‹ค๋Š” ๊ฑธ ์•Œ ์ˆ˜ ์žˆ์–ด์š”.
  • key ๊ฐ€ ๋ฐ”๋€Œ๋ฉด React ๊ฐ€ ์™„์ „ํžˆ ์ƒˆ ์ปดํฌ๋„ŒํŠธ๋ฅผ ๋งˆ์šดํŠธํ•œ๋‹ค๋Š” ๊ฑธ ์ดํ•ดํ•  ์ˆ˜ ์žˆ์–ด์š”.

๐Ÿค” ์ž ๊น, ๋จผ์ € ์ƒ๊ฐํ•ด๋ด
๋ฆฌ์ŠคํŠธ๋ฅผ ๋ Œ๋”๋งํ•  ๋•Œ key ๊ฐ€ ์—†์œผ๋ฉด ๊ฒฝ๊ณ ๊ฐ€ ๋‚˜์˜ค๋Š”๋ฐ, ๊ทธ ์ด์œ ๊ฐ€ ๋‹จ์ˆœํžˆ "React ๋‚ด๋ถ€ ์ตœ์ ํ™”" ๋•Œ๋ฌธ๋งŒ์ผ๊นŒ์š”?
key ๊ฐ€ "์ฃผ๋ฏผ๋“ฑ๋ก๋ฒˆํ˜ธ" ๋ผ๋ฉด, ๋ฒˆํ˜ธ๊ฐ€ ๋ฐ”๋€Œ๋ฉด ์–ด๋–ค ์ผ์ด ์ƒ๊ธธ๊นŒ์š”?

key โ€” Key (ํ‚ค) ๋Š” ๋ผํ‹ด์–ด clavis(์—ด์‡ ) ์—์„œ ์˜จ ๋‹จ์–ด์˜ˆ์š”. React ์—์„œ key ๋Š” ํ˜•์ œ ์ปดํฌ๋„ŒํŠธ๋“ค ์‚ฌ์ด์—์„œ ํŠน์ • ์ธ์Šคํ„ด์Šค๋ฅผ ๊ตฌ๋ณ„ํ•˜๋Š” ๊ณ ์œ  ์‹๋ณ„์ž์˜ˆ์š”.

๋Œ€๋ถ€๋ถ„์˜ ๊ฐœ๋ฐœ์ž๋Š” key ๋ฅผ "๋ฆฌ์ŠคํŠธ ๋ Œ๋”๋ง ์‹œ ๊ฒฝ๊ณ ๋ฅผ ์—†์• ๊ธฐ ์œ„ํ•œ ๊ท€์ฐฎ์€ ๊ฒƒ" ์ •๋„๋กœ ์•Œ์•„์š”. ํ•˜์ง€๋งŒ key ์˜ ์ง„์งœ ์—ญํ• ์€ ํ›จ์”ฌ ๊ฐ•๋ ฅํ•ด์š”:

key ๋Š” "๊ฐ™์€ ์œ„์น˜, ๊ฐ™์€ ํƒ€์ž…" ์ด๋ผ๋„ ๋‹ค๋ฅธ ์ธ์Šคํ„ด์Šค์ž„์„ ๋ช…์‹œ์ ์œผ๋กœ ์„ ์–ธํ•˜๋Š” ์ˆ˜๋‹จ์ด์—์š”.

// โœ… key๋กœ ์˜์ฒ ์ด์˜ Scoreboard ๋ฒ„๊ทธ ์™„๋ฒฝ ํ•ด๊ฒฐ
function Scoreboard() {
  const [isPlayerA, setIsPlayerA] = useState(true);
 
  return (
    <div>
      {isPlayerA ? (
        <Counter
          key="์˜ํ˜ธ"   // key="์˜ํ˜ธ" โ†’ ์ด ์ž๋ฆฌ์˜ ์ฃผ๋ฏผ๋“ฑ๋ก๋ฒˆํ˜ธ
          person="์˜ํ˜ธ"
        />
      ) : (
        <Counter
          key="์˜์ฒ "   // key="์˜์ฒ " โ†’ ๋‹ค๋ฅธ ์ฃผ๋ฏผ๋“ฑ๋ก๋ฒˆํ˜ธ โ†’ ์™„์ „ํžˆ ๋‹ค๋ฅธ ์ธ์Šคํ„ด์Šค!
          person="์˜์ฒ "
        />
      )}
      {/*
        isPlayerA๊ฐ€ true โ†’ false ๋กœ ๋ฐ”๋€” ๋•Œ:
        - ์ด์ „ ํŠธ๋ฆฌ: Counter (key="์˜ํ˜ธ", score=5)
        - ์ƒˆ ํŠธ๋ฆฌ:   Counter (key="์˜์ฒ ")
        - React ํŒ๋‹จ: "key๊ฐ€ ๋‹ค๋ฅด๋‹ค! ์™„์ „ํžˆ ๋‹ค๋ฅธ ์ธ์Šคํ„ด์Šค๋‹ค!"
        - ๋™์ž‘: key="์˜ํ˜ธ" Counter ์–ธ๋งˆ์šดํŠธ โ†’ key="์˜์ฒ " Counter ์ƒˆ๋กœ ๋งˆ์šดํŠธ
        - ๊ฒฐ๊ณผ: score๋Š” 0์œผ๋กœ ๋ฆฌ์…‹๋จ โœ…
      */}
      <button onClick={() => setIsPlayerA(!isPlayerA)}>๋‹ค์Œ ํ”Œ๋ ˆ์ด์–ด</button>
    </div>
  );
}

key ๋ฅผ ๋ถ€์—ฌํ•˜๋ฉด React ๋Š” ํƒ€์ž…์ด ๊ฐ™๋”๋ผ๋„ "๋‹ค๋ฅธ key = ๋‹ค๋ฅธ ์ธ์Šคํ„ด์Šค" ๋กœ ์ธ์‹ํ•ด์š”. ์ด์ „ key ๋ฅผ ๊ฐ€์ง„ ์ปดํฌ๋„ŒํŠธ๋ฅผ ์–ธ๋งˆ์šดํŠธํ•˜๊ณ , ์ƒˆ key ๋ฅผ ๊ฐ€์ง„ ์ปดํฌ๋„ŒํŠธ๋ฅผ ์™„์ „ํžˆ ์ƒˆ๋กœ ๋งˆ์šดํŠธํ•ด์š”.

์ด ๋™์ž‘์„ ๋‹ค์ด์–ด๊ทธ๋žจ์œผ๋กœ ๋ณด๋ฉด:

key="์˜ํ˜ธ" ์ผ ๋•Œ์˜ ํŠธ๋ฆฌ:
Scoreboard
โ””โ”€โ”€ div
    โ””โ”€โ”€ Counter [key="์˜ํ˜ธ"] (score=5)

key="์˜์ฒ " ๋กœ ๋ณ€๊ฒฝ ํ›„ ํŠธ๋ฆฌ:
Scoreboard
โ””โ”€โ”€ div
    โ””โ”€โ”€ Counter [key="์˜์ฒ "] (score=0)  โ† ์ƒˆ๋กœ ๋งˆ์šดํŠธ! score=0์—์„œ ์‹œ์ž‘

// React๋Š” key="์˜ํ˜ธ" Counter๋ฅผ ์™„์ „ํžˆ ์–ธ๋งˆ์šดํŠธ(ํŒŒ๊ดด)ํ•˜๊ณ 
// key="์˜์ฒ " Counter๋ฅผ ์ฒ˜์Œ๋ถ€ํ„ฐ ์ƒˆ๋กœ ๋งˆ์šดํŠธํ–ˆ๋‹ค

๐Ÿ“– ์šฉ์–ด: ์žฌ์กฐ์ •(Reconciliation)
React ๊ฐ€ ์ด์ „ ๋ Œ๋” ํŠธ๋ฆฌ์™€ ์ƒˆ ๋ Œ๋” ํŠธ๋ฆฌ๋ฅผ ๋น„๊ต(diff)ํ•ด์„œ ์ตœ์†Œํ•œ์˜ DOM ์—…๋ฐ์ดํŠธ๋งŒ ์ˆ˜ํ–‰ํ•˜๋Š” ๊ณผ์ •์ด์—์š”. key ๋Š” ์ด ์žฌ์กฐ์ • ๊ณผ์ •์—์„œ "๊ฐ™์€ ๋†ˆ์ด๋ƒ" ๋ฅผ ํŒ๋‹จํ•˜๋Š” ํ•ต์‹ฌ ๊ธฐ์ค€์ด์—์š”.

key ๊ฐ€ ์—†์„ ๋•Œ ๋ชฉ๋ก ๋ Œ๋”๋ง์ด ์œ„ํ—˜ํ•œ ์ด์œ 

// โŒ key ์—†๋Š” ๋ชฉ๋ก ๋ Œ๋”๋ง์˜ ์žฌ์•™
const studyMembers = ['์˜์ˆ˜', '์˜์ฒ ', '์˜ํ˜ธ'];
 
function MemberList() {
  return (
    <ul>
      {studyMembers.map((name) => (
        <MemberItem name={name} />  // key ์—†์Œ!
      ))}
    </ul>
  );
}
 
// ๋งŒ์•ฝ '์˜์ˆ˜'๋ฅผ ๋ชฉ๋ก ์•ž์—์„œ ์ œ๊ฑฐํ•˜๋ฉด:
// ๋ณ€๊ฒฝ ์ „: ['์˜์ˆ˜', '์˜์ฒ ', '์˜ํ˜ธ']
// ๋ณ€๊ฒฝ ํ›„: ['์˜์ฒ ', '์˜ํ˜ธ']
 
// React๋Š” position์œผ๋กœ๋งŒ ๋น„๊ต:
// ์œ„์น˜ 0: '์˜์ˆ˜' MemberItem โ†’ '์˜์ฒ ' MemberItem (์—…๋ฐ์ดํŠธ)
// ์œ„์น˜ 1: '์˜์ฒ ' MemberItem โ†’ '์˜ํ˜ธ' MemberItem (์—…๋ฐ์ดํŠธ)
// ์œ„์น˜ 2: '์˜ํ˜ธ' MemberItem โ†’ ์—†์Œ (์ œ๊ฑฐ)
 
// ๊ฒฐ๊ณผ: 3๊ฐœ๊ฐ€ 2๊ฐœ์˜ ์—…๋ฐ์ดํŠธ + 1๊ฐœ ์ œ๊ฑฐ๋กœ ์ฒ˜๋ฆฌ๋จ
// ๋งŒ์•ฝ MemberItem ์•ˆ์— ์ƒํƒœ๊ฐ€ ์žˆ๋‹ค๋ฉด ์ƒํƒœ๊ฐ€ ์—‰๋šฑํ•œ ์•„์ดํ…œ์œผ๋กœ ์˜ฎ๊ฒจ๊ฐ€๋Š” ๋ฒ„๊ทธ ๋ฐœ์ƒ!
// โœ… key ์žˆ๋Š” ๋ชฉ๋ก ๋ Œ๋”๋ง โ€” ์˜ฌ๋ฐ”๋ฅธ ๋ฐฉ์‹
function MemberList() {
  return (
    <ul>
      {studyMembers.map((name) => (
        <MemberItem key={name} name={name} />  // key๋กœ ์‹ ์› ๋ช…ํ™•ํžˆ ํ‘œ์‹œ
      ))}
    </ul>
  );
}
 
// ์ด์ œ React๋Š” key๋กœ ๋ˆ„๊ฐ€ ๋ˆ„๊ตฐ์ง€ ์ถ”์ :
// key="์˜์ˆ˜" ์ œ๊ฑฐ โ†’ ํ•ด๋‹น ์ธ์Šคํ„ด์Šค๋งŒ ์–ธ๋งˆ์šดํŠธ
// key="์˜์ฒ ", key="์˜ํ˜ธ" ๋Š” ์œ„์น˜๊ฐ€ ๋ฐ”๋€Œ์–ด๋„ ์ƒํƒœ ์œ ์ง€๋จ โœ…

๐Ÿ’ก ํ•œ ์ค„๋กœ ๊ธฐ์–ตํ•˜๊ธฐ
key ๋Š” ์ฃผ๋ฏผ๋“ฑ๋ก๋ฒˆํ˜ธ์˜ˆ์š”. ๋ฒˆํ˜ธ๊ฐ€ ๋ฐ”๋€Œ๋ฉด React ๋Š” ๊ธฐ์กด ๊ฑฐ์ฃผ์ž๋ฅผ ์ซ“์•„๋‚ด๊ณ (์–ธ๋งˆ์šดํŠธ) ์ƒˆ ์‚ฌ๋žŒ์„ ์ž…์ฃผ์‹œ์ผœ์š”(์ƒˆ ๋งˆ์šดํŠธ). ๋ฒˆํ˜ธ๊ฐ€ ๊ฐ™์œผ๋ฉด ์ด์‚ฌ๊ฐ€๋„(์œ„์น˜ ์ด๋™) ๊ฐ™์€ ์‚ฌ๋žŒ์œผ๋กœ ์ธ์‹ํ•ด์š”.


๐Ÿงฉ key ํŠธ๋ฆญ ์‹ค๋ฌด ํŒจํ„ด ๐ŸŸก

๐ŸŽฏ ์ด ์„น์…˜์„ ์ฝ๊ณ  ๋‚˜๋ฉด:

  • ํผ ์ œ์ถœ ํ›„ ๊ฐ•์ œ ๋ฆฌ์…‹์— key ๋ฅผ ํ™œ์šฉํ•˜๋Š” ๋ฐฉ๋ฒ•์„ ์‹ค๋ฌด์— ๋ฐ”๋กœ ์ ์šฉํ•  ์ˆ˜ ์žˆ์–ด์š”.
  • ์ฑ„ํŒ…์ฐฝ์ฒ˜๋Ÿผ "๊ฐ™์€ ์ปดํฌ๋„ŒํŠธ์ธ๋ฐ ๋‹ค๋ฅธ ์ธ์Šคํ„ด์Šค์—ฌ์•ผ ํ•˜๋Š”" ์ผ€์ด์Šค๋ฅผ ์ฒ˜๋ฆฌํ•  ์ˆ˜ ์žˆ์–ด์š”.

ํŒจํ„ด 1: ํผ ๊ฐ•์ œ ๋ฆฌ์…‹ ๐Ÿ”‘

์˜์ˆ˜๋„ค ์ปค๋ฎค๋‹ˆํ‹ฐ์—์„œ ๋Œ“๊ธ€์„ ์ž‘์„ฑํ•˜๋ฉด ํผ์ด ์ž๋™์œผ๋กœ ๋น„์›Œ์ ธ์•ผ ํ•ด์š”. ๊ฐ€์žฅ ๋‹จ์ˆœํ•œ ํ•ด๊ฒฐ์ฑ…์€ key ๋ฅผ ์ œ์ถœํ•  ๋•Œ๋งˆ๋‹ค ๋ฐ”๊พธ๋Š” ๊ฑฐ์˜ˆ์š”.

// โœ… ํŒจํ„ด 1: key๋ฅผ ์ˆซ์ž๋กœ ๊ด€๋ฆฌํ•ด์„œ ์ œ์ถœ ์‹œ ํผ ๊ฐ•์ œ ๋ฆฌ์…‹
function CommentSection({ postId }) {
  const [formKey, setFormKey] = useState(0); // ํผ์˜ ์ฃผ๋ฏผ๋“ฑ๋ก๋ฒˆํ˜ธ ์—ญํ• 
 
  const handleCommentSubmit = async (content) => {
    await submitComment({ postId, content }); // API ํ˜ธ์ถœ
    setFormKey((prev) => prev + 1);
    // key๊ฐ€ 0 โ†’ 1 ๋กœ ๋ฐ”๋€œ โ†’ React๋Š” ์™„์ „ํžˆ ์ƒˆ PostCommentForm์„ ๋งˆ์šดํŠธ
    // PostCommentForm ๋‚ด๋ถ€์˜ ๋ชจ๋“  useState๊ฐ€ ์ดˆ๊ธฐ๊ฐ’์œผ๋กœ ๋ฆฌ์…‹๋จ
  };
 
  return (
    <div>
      <h3>๋Œ“๊ธ€ ์ž‘์„ฑ</h3>
      <PostCommentForm
        key={formKey}           // formKey๊ฐ€ ๋ฐ”๋€” ๋•Œ๋งˆ๋‹ค ์ƒˆ ์ธ์Šคํ„ด์Šค๋กœ ๊ต์ฒด๋จ
        onSubmit={handleCommentSubmit}
      />
    </div>
  );
}
 
// PostCommentForm ๋‚ด๋ถ€ (์ƒํƒœ๊ฐ€ ์—ฌ๋Ÿฌ ๊ฐœ์ผ ๋•Œ ํŠนํžˆ ์œ ์šฉ)
function PostCommentForm({ onSubmit }) {
  const [content, setContent] = useState('');       // ๋Œ“๊ธ€ ๋‚ด์šฉ
  const [isAnonymous, setIsAnonymous] = useState(false); // ์ต๋ช… ์—ฌ๋ถ€
  const [mood, setMood] = useState('neutral');      // ๊ฐ์ • ํƒœ๊ทธ
 
  // key๊ฐ€ ๋ฐ”๋€Œ๋ฉด ์ด ์ƒํƒœ๋“ค์ด ๋ชจ๋‘ ์ดˆ๊ธฐ๊ฐ’์œผ๋กœ ๋ฆฌ์…‹๋จ
  // ์ผ์ผ์ด setContent(''), setIsAnonymous(false), setMood('neutral') ์•ˆ ํ•ด๋„ ๋จ!
 
  return (
    <form onSubmit={(e) => { e.preventDefault(); onSubmit(content); }}>
      <textarea value={content} onChange={(e) => setContent(e.target.value)} />
      {/* ... ๊ธฐํƒ€ ํ•„๋“œ๋“ค */}
      <button type="submit">๋Œ“๊ธ€ ์ž‘์„ฑ</button>
    </form>
  );
}

์™œ ์ด ๋ฐฉ์‹์ด ์ข‹์€๊ฐ€? PostCommentForm ๋‚ด๋ถ€ ์ƒํƒœ๊ฐ€ 5๊ฐœ๋“  10๊ฐœ๋“  key ํ•˜๋‚˜๋งŒ ๋ฐ”๊พธ๋ฉด ๋ชจ๋‘ ํ•œ ๋ฒˆ์— ๋ฆฌ์…‹๋ผ์š”. ์ผ์ผ์ด setState ๋กœ ์ดˆ๊ธฐํ™”ํ•˜๋Š” ์ฝ”๋“œ๊ฐ€ ํ•„์š” ์—†์–ด์š”.

ํŒจํ„ด 2: ์ฑ„ํŒ…์ฐฝ ์ธ์Šคํ„ด์Šค ๋ถ„๋ฆฌ ๐Ÿ—‚๏ธ

์˜์ˆ˜๋„ค ์ปค๋ฎค๋‹ˆํ‹ฐ์—๋Š” 1:1 ์ฑ„ํŒ… ๊ธฐ๋Šฅ์ด ์žˆ์–ด์š”. ์˜ํ˜ธ์™€ ๋Œ€ํ™”ํ•˜๋‹ค๊ฐ€ ์˜์ฒ ๋กœ ์ „ํ™˜ํ•˜๋ฉด, ์ฑ„ํŒ… ์ž…๋ ฅ์ฐฝ์ด ๋น„์›Œ์ง€๊ณ  ์˜์ฒ ๊ณผ์˜ ๋Œ€ํ™” ์ด๋ ฅ์ด ๋กœ๋“œ๋˜์–ด์•ผ ํ•ด์š”.

// โœ… ํŒจํ„ด 2: ์—ฐ๋ฝ์ฒ˜๋ณ„ ChatWindow๋ฅผ ์™„์ „ํžˆ ๋‹ค๋ฅธ ์ธ์Šคํ„ด์Šค๋กœ ๋ถ„๋ฆฌ
function DirectMessagePage() {
  const [selectedContact, setSelectedContact] = useState('์˜ํ˜ธ');
 
  return (
    <div style={{ display: 'flex' }}>
      {/* ์—ฐ๋ฝ์ฒ˜ ๋ชฉ๋ก */}
      <ContactList
        onSelect={setSelectedContact}
        selected={selectedContact}
      />
 
      {/*
        key={selectedContact}๋กœ ์—ฐ๋ฝ์ฒ˜๋งˆ๋‹ค ์™„์ „ํžˆ ๋‹ค๋ฅธ ChatWindow ์ธ์Šคํ„ด์Šค ์ƒ์„ฑ
        ์˜ํ˜ธ โ†’ ์˜์ฒ  ์ „ํ™˜ ์‹œ:
        - key="์˜ํ˜ธ" ChatWindow ์–ธ๋งˆ์šดํŠธ (์ž…๋ ฅ ์ค‘์ธ ๋‚ด์šฉ, ์Šคํฌ๋กค ์œ„์น˜ ๋“ฑ ๋ชจ๋‘ ์ดˆ๊ธฐํ™”)
        - key="์˜์ฒ " ChatWindow ์ƒˆ๋กœ ๋งˆ์šดํŠธ (์˜์ฒ ๊ณผ์˜ ๋Œ€ํ™” ์ด๋ ฅ ๋กœ๋“œ ์‹œ์ž‘)
      */}
      <ChatWindow
        key={selectedContact}  // ์—ฐ๋ฝ์ฒ˜๊ฐ€ ๋ฐ”๋€Œ๋ฉด ์™„์ „ํžˆ ์ƒˆ ์ฑ„ํŒ…์ฐฝ์„ ์—ด์–ด์š”
        contact={selectedContact}
      />
    </div>
  );
}
 
function ChatWindow({ contact }) {
  const [message, setMessage] = useState('');      // ํ˜„์žฌ ์ž…๋ ฅ ์ค‘์ธ ๋ฉ”์‹œ์ง€
  const [messages, setMessages] = useState([]);    // ๋Œ€ํ™” ์ด๋ ฅ
 
  // contact๊ฐ€ ๋ฐ”๋€Œ๋ฉด(= key๊ฐ€ ๋ฐ”๋€Œ๋ฉด) ์ด useEffect๊ฐ€ ์ƒˆ ์ธ์Šคํ„ด์Šค์—์„œ ์‹คํ–‰๋จ
  // message, messages ๋ชจ๋‘ ์ดˆ๊ธฐ๊ฐ’์—์„œ ์‹œ์ž‘
  useEffect(() => {
    loadChatHistory(contact).then(setMessages); // ํ•ด๋‹น ์—ฐ๋ฝ์ฒ˜์˜ ์ฑ„ํŒ… ์ด๋ ฅ ๋กœ๋“œ
  }, []); // ๋งˆ์šดํŠธ ์‹œ ํ•œ ๋ฒˆ๋งŒ ์‹คํ–‰ (key ๋ณ€๊ฒฝ = ์ƒˆ ๋งˆ์šดํŠธ์ด๋ฏ€๋กœ OK)
 
  return (
    <div>
      <h2>{contact} ์™€์˜ ๋Œ€ํ™”</h2>
      {/* ๋Œ€ํ™” ์ด๋ ฅ ํ‘œ์‹œ */}
      <div>{messages.map((msg) => <MessageBubble key={msg.id} msg={msg} />)}</div>
      {/* ๋ฉ”์‹œ์ง€ ์ž…๋ ฅ */}
      <input value={message} onChange={(e) => setMessage(e.target.value)} />
    </div>
  );
}

ํŒจํ„ด 3: ๋™์ผ ํŽ˜์ด์ง€ ๋‚ด ์กฐ๊ฑด๋ถ€ ์ปดํฌ๋„ŒํŠธ ์ƒํƒœ ๋ถ„๋ฆฌ ๐Ÿ”„

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

// โœ… ํŒจํ„ด 3: postId๋ฅผ key๋กœ ์‚ฌ์šฉํ•ด์„œ ํฌ์ŠคํŠธ๋ณ„ ์ƒํƒœ ๊ฒฉ๋ฆฌ
function PostEditor({ postId }) {
  // postId๊ฐ€ ๋ฐ”๋€Œ๋ฉด(๋‹ค๋ฅธ ํฌ์ŠคํŠธ๋ฅผ ํŽธ์ง‘ํ•˜๋Ÿฌ ๊ฐ€๋ฉด) ์—๋””ํ„ฐ ์ „์ฒด๊ฐ€ ๋ฆฌ์…‹๋จ
  return (
    <PostEditorContent
      key={postId}  // postId = ์—๋””ํ„ฐ์˜ ์‹ ์›์ฆ๋ช…์„œ
      postId={postId}
    />
  );
}
 
function PostEditorContent({ postId }) {
  const [title, setTitle] = useState('');         // ์ œ๋ชฉ ์ž…๋ ฅ ์ƒํƒœ
  const [content, setContent] = useState('');     // ๋‚ด์šฉ ์ž…๋ ฅ ์ƒํƒœ
  const [isPreview, setIsPreview] = useState(false); // ๋ฏธ๋ฆฌ๋ณด๊ธฐ ๋ชจ๋“œ
 
  // postId๊ฐ€ ๊ฐ™์œผ๋ฉด(๊ฐ™์€ ํฌ์ŠคํŠธ๋ฅผ ๊ณ„์† ํŽธ์ง‘) ์ƒํƒœ ์œ ์ง€
  // postId๊ฐ€ ๋‹ฌ๋ผ์ง€๋ฉด(๋‹ค๋ฅธ ํฌ์ŠคํŠธ๋กœ ์ด๋™) key ๋ณ€๊ฒฝ โ†’ ์ƒํƒœ ๋ฆฌ์…‹ โ†’ ์ด useEffect ์žฌ์‹คํ–‰
  useEffect(() => {
    loadPostData(postId).then(({ title, content }) => {
      setTitle(title);   // ๊ธฐ์กด ํฌ์ŠคํŠธ ๋ฐ์ดํ„ฐ๋กœ ์ดˆ๊ธฐํ™”
      setContent(content);
    });
  }, []); // ๋งˆ์šดํŠธ ์‹œ ํ•œ ๋ฒˆ๋งŒ (key ๋ณ€๊ฒฝ = ์ƒˆ ๋งˆ์šดํŠธ)
 
  return isPreview
    ? <PostPreview title={title} content={content} />
    : <PostForm title={title} content={content} onTitleChange={setTitle} onContentChange={setContent} />;
}

ํŒจํ„ด 4: ๊ฒ€์ƒ‰์–ด๋ณ„ ๊ฒฐ๊ณผ ๋ชฉ๋ก ์ƒํƒœ ๋ถ„๋ฆฌ ๐Ÿ”

// โœ… ํŒจํ„ด 4: ๊ฒ€์ƒ‰์–ด๊ฐ€ ๋ฐ”๋€” ๋•Œ๋งˆ๋‹ค ๊ฒฐ๊ณผ ๋ชฉ๋ก ์ƒํƒœ๋ฅผ ๋ฆฌ์…‹
function SearchPage() {
  const [query, setQuery] = useState('');
  const [submittedQuery, setSubmittedQuery] = useState('');
 
  return (
    <div>
      <input
        value={query}
        onChange={(e) => setQuery(e.target.value)}
        placeholder="์Šคํ„ฐ๋”” ๊ฒ€์ƒ‰..."
      />
      <button onClick={() => setSubmittedQuery(query)}>๊ฒ€์ƒ‰</button>
 
      {/*
        submittedQuery๊ฐ€ ๋ฐ”๋€” ๋•Œ๋งˆ๋‹ค SearchResults๋ฅผ ์™„์ „ํžˆ ์ƒˆ ์ธ์Šคํ„ด์Šค๋กœ ๊ต์ฒด
        โ†’ SearchResults ๋‚ด๋ถ€์˜ ํŽ˜์ด์ง€๋„ค์ด์…˜ ์ƒํƒœ(currentPage), ์ •๋ ฌ ์ƒํƒœ ๋“ฑ์ด ๋ฆฌ์…‹๋จ
      */}
      {submittedQuery && (
        <SearchResults
          key={submittedQuery}   // ๊ฒ€์ƒ‰์–ด๋งˆ๋‹ค ์ƒˆ ์ธ์Šคํ„ด์Šค!
          query={submittedQuery}
        />
      )}
    </div>
  );
}

๐Ÿ’ก ํ•œ ์ค„๋กœ ๊ธฐ์–ตํ•˜๊ธฐ
key ํŠธ๋ฆญ์˜ ํ•ต์‹ฌ์€ "์–ธ์ œ ์ƒํƒœ๋ฅผ ๋ฆฌ์…‹ํ• ์ง€" ๋ฅผ ๊ฒฐ์ •ํ•˜๋Š” ๊ธฐ์ค€๊ฐ’์„ key ์— ๋„ฃ๋Š” ๊ฑฐ์˜ˆ์š”. ์ œ์ถœ ์นด์šดํ„ฐ, ์—ฐ๋ฝ์ฒ˜ ID, ํฌ์ŠคํŠธ ID, ๊ฒ€์ƒ‰์–ด โ€” ์ด ๊ธฐ์ค€๊ฐ’์ด ๋ฐ”๋€Œ๋ฉด ์ปดํฌ๋„ŒํŠธ๋„ ์ƒˆ๋กœ ํƒœ์–ด๋‚˜์š”.


๐Ÿงฉ ์ ˆ๋Œ€ ๊ธˆ์ง€: ๋ Œ๋” ํ•จ์ˆ˜ ์•ˆ์— ์ปดํฌ๋„ŒํŠธ ์ค‘์ฒฉ ์ •์˜ ๐Ÿ”ด

๐ŸŽฏ ์ด ์„น์…˜์„ ์ฝ๊ณ  ๋‚˜๋ฉด:

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

์ด๊ฑด React ํ•™์Šต์—์„œ ๊ฐ€์žฅ ์น˜๋ช…์ ์ด๊ณ  ์ง„๋‹จํ•˜๊ธฐ ์–ด๋ ค์šด ๋ฒ„๊ทธ ํŒจํ„ด ์ค‘ ํ•˜๋‚˜์˜ˆ์š”. ์ฝ”๋“œ ๋ฆฌ๋ทฐ์—์„œ๋„ ๋†“์น˜๊ธฐ ์‰ฌ์šด ์ง€๋ขฐ์˜ˆ์š”.

// ๐Ÿšจ ์ ˆ๋Œ€ ๊ธˆ์ง€ ํŒจํ„ด โ€” ๋ Œ๋” ํ•จ์ˆ˜ ์•ˆ์— ์ปดํฌ๋„ŒํŠธ ์ •์˜
function StudyPostList() {
  const [searchQuery, setSearchQuery] = useState('');
 
  // ๐Ÿ’ฃ ๋งค ๋ Œ๋”๋งˆ๋‹ค ์ƒˆ๋กœ์šด ํ•จ์ˆ˜ ์ฐธ์กฐ๊ฐ€ ๋งŒ๋“ค์–ด์ง!
  // StudyPostList๊ฐ€ ๋ Œ๋”๋ง๋  ๋•Œ๋งˆ๋‹ค SearchInput์€ ์™„์ „ํžˆ ์ƒˆ๋กœ์šด ํ•จ์ˆ˜๊ฐ€ ๋ผ์š”
  function SearchInput() {
    const [inputValue, setInputValue] = useState('');
 
    return (
      <input
        value={inputValue}
        onChange={(e) => setInputValue(e.target.value)}
        placeholder="์Šคํ„ฐ๋”” ๊ฒ€์ƒ‰..."
      />
    );
  }
 
  const posts = filterPosts(allPosts, searchQuery); // ๊ฒ€์ƒ‰ ํ•„ํ„ฐ๋ง
 
  return (
    <div>
      {/*
        SearchInput์€ ๋งค ๋ Œ๋”๋งˆ๋‹ค ์ƒˆ๋กœ์šด ํ•จ์ˆ˜ ์ฐธ์กฐ = ์ƒˆ๋กœ์šด ์ปดํฌ๋„ŒํŠธ ํƒ€์ž…
        React ํŒ๋‹จ: "์ด์ „ ๋ Œ๋”์˜ SearchInput๊ณผ ์ด๋ฒˆ ๋ Œ๋”์˜ SearchInput์€ ๋‹ค๋ฅธ ํƒ€์ž…์ด๋‹ค!"
        ๋™์ž‘: ๋งค ๋ Œ๋”๋งˆ๋‹ค SearchInput์„ ์–ธ๋งˆ์šดํŠธ ํ›„ ์ƒˆ๋กœ ๋งˆ์šดํŠธ
        ๊ฒฐ๊ณผ: inputValue ์ƒํƒœ๊ฐ€ ๋งค ๋ Œ๋”๋งˆ๋‹ค '' ๋กœ ๋ฆฌ์…‹ โ†’ ๊ธ€์ž๋ฅผ ์ž…๋ ฅํ•  ์ˆ˜ ์—†์Œ! ๐Ÿ˜ฑ
      */}
      <SearchInput />
      <ul>
        {posts.map((post) => (
          <PostItem key={post.id} post={post} />
        ))}
      </ul>
    </div>
  );
}

์™œ ์ด๋Ÿฐ ์ผ์ด ๋ฒŒ์–ด์ง€๋‚˜์š”?

JavaScript ์—์„œ ํ•จ์ˆ˜๋Š” ๋งค๋ฒˆ ํ˜ธ์ถœ๋  ๋•Œ๋งˆ๋‹ค ์ƒˆ๋กœ์šด ๊ฐ์ฒด๋ฅผ ๋งŒ๋“ค์–ด์š”. StudyPostList ๊ฐ€ ๋ Œ๋”๋ง๋  ๋•Œ๋งˆ๋‹ค SearchInput ์ด๋ผ๋Š” ๋ณ€์ˆ˜์— ์™„์ „ํžˆ ์ƒˆ๋กœ์šด ํ•จ์ˆ˜ ๊ฐ์ฒด๊ฐ€ ๋‹ด๊ฒจ์š”.

React ๋Š” ์ปดํฌ๋„ŒํŠธ ํƒ€์ž…์„ ์ฐธ์กฐ(reference) ๋กœ ๋น„๊ตํ•ด์š”. ์ด์ „ ๋ Œ๋”์˜ SearchInput ๊ณผ ์ด๋ฒˆ ๋ Œ๋”์˜ SearchInput ์€ ์ด๋ฆ„์ด ๊ฐ™์•„๋„ ๋ฉ”๋ชจ๋ฆฌ ์ฃผ์†Œ๊ฐ€ ๋‹ฌ๋ผ์š”. ๊ทธ๋ž˜์„œ React ๋Š” "์™„์ „ํžˆ ๋‹ค๋ฅธ ํƒ€์ž…์ด ์™”๋‹ค!" ๋ผ๊ณ  ํŒ๋‹จํ•˜๊ณ  ์–ธ๋งˆ์šดํŠธ ํ›„ ์ƒˆ๋กœ ๋งˆ์šดํŠธํ•ด์š”.

// ๐Ÿงช ๊ฐœ๋… ์ฆ๋ช… (์˜์‚ฌ ์ฝ”๋“œ)
const render1 = () => {
  function SearchInput() { ... }  // ์ฃผ์†Œ: 0x1234
  return <SearchInput />;
};
 
const render2 = () => {
  function SearchInput() { ... }  // ์ฃผ์†Œ: 0x5678 (๋‹ค๋ฅธ ํ•จ์ˆ˜ ๊ฐ์ฒด!)
  return <SearchInput />;
};
 
// React๊ฐ€ ๋ณด๋Š” ๊ฒƒ:
// render1์˜ SearchInput: type = 0x1234
// render2์˜ SearchInput: type = 0x5678
// ๊ฒฐ๋ก : ํƒ€์ž…์ด ๋‹ฌ๋ผ์กŒ๋‹ค โ†’ ์–ธ๋งˆ์šดํŠธ + ์ƒˆ ๋งˆ์šดํŠธ!

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

// โœ… ์˜ฌ๋ฐ”๋ฅธ ํ•ด๊ฒฐ์ฑ…: ์ปดํฌ๋„ŒํŠธ๋ฅผ ๋ Œ๋” ํ•จ์ˆ˜ ๋ฐ”๊นฅ์— ์ •์˜
// SearchInput์„ ๋ชจ๋“ˆ ์ตœ์ƒ์œ„ ๋ ˆ๋ฒจ์— ์ •์˜ โ†’ ํ•จ์ˆ˜ ์ฐธ์กฐ๊ฐ€ ๋ถˆ๋ณ€(stable reference)
function SearchInput({ onSearch }) {
  const [inputValue, setInputValue] = useState('');
 
  return (
    <input
      value={inputValue}
      onChange={(e) => setInputValue(e.target.value)}
      onKeyDown={(e) => e.key === 'Enter' && onSearch(inputValue)}
      placeholder="์Šคํ„ฐ๋”” ๊ฒ€์ƒ‰..."
    />
  );
}
 
// StudyPostList๋Š” ์ด์ œ SearchInput์„ importํ•ด์„œ ์‚ฌ์šฉ
function StudyPostList() {
  const [searchQuery, setSearchQuery] = useState('');
 
  const posts = filterPosts(allPosts, searchQuery);
 
  return (
    <div>
      {/* SearchInput์€ ํ•ญ์ƒ ๊ฐ™์€ ํ•จ์ˆ˜ ์ฐธ์กฐ โ†’ ๋ Œ๋”๋งˆ๋‹ค ์žฌ์‚ฌ์šฉ โ†’ ์ƒํƒœ ์œ ์ง€ โœ… */}
      <SearchInput onSearch={setSearchQuery} />
      <ul>
        {posts.map((post) => (
          <PostItem key={post.id} post={post} />
        ))}
      </ul>
    </div>
  );
}

Before / After ํ•œ๋ˆˆ์— ๋น„๊ต:

๊ตฌ๋ถ„โŒ ๋ Œ๋” ํ•จ์ˆ˜ ๋‚ด๋ถ€ ์ •์˜โœ… ๋ชจ๋“ˆ ์ตœ์ƒ์œ„ ์ •์˜
ํ•จ์ˆ˜ ์ฐธ์กฐ๋งค ๋ Œ๋”๋งˆ๋‹ค ์ƒˆ ๊ฐ์ฒด๋ชจ๋“ˆ ๋กœ๋“œ ์‹œ ๋‹จ ํ•œ ๋ฒˆ ์ƒ์„ฑ
React ์ธ์‹๋งค๋ฒˆ "์ƒˆ ํƒ€์ž…"ํ•ญ์ƒ "๊ฐ™์€ ํƒ€์ž…"
์ปดํฌ๋„ŒํŠธ ๋™์ž‘๋งค ๋ Œ๋”๋งˆ๋‹ค ์–ธ๋งˆ์šดํŠธ + ์ƒˆ ๋งˆ์šดํŠธ์ƒํƒœ ์œ ์ง€ํ•˜๋ฉฐ ์—…๋ฐ์ดํŠธ
์ƒํƒœ๋งค ๋ Œ๋”๋งˆ๋‹ค ์ดˆ๊ธฐํ™”์ •์ƒ ์œ ์ง€
์„ฑ๋Šฅ๋งค๋ฒˆ DOM ์žฌ์ƒ์„ฑ์ตœ์†Œํ•œ์˜ DOM ์—…๋ฐ์ดํŠธ

ํ™”์‚ดํ‘œ ํ•จ์ˆ˜๋„ ๋™์ผํ•œ ๊ทœ์น™ ์ ์šฉ:

// โŒ ์ด๊ฒƒ๋„ ์ ˆ๋Œ€ ๊ธˆ์ง€ โ€” ํ™”์‚ดํ‘œ ํ•จ์ˆ˜๋กœ ์ปดํฌ๋„ŒํŠธ ์ •์˜๋„ ๋™์ผํ•œ ๋ฌธ์ œ
function ParentComponent() {
  const ChildComponent = () => {  // ๋งค ๋ Œ๋”๋งˆ๋‹ค ์ƒˆ ํ•จ์ˆ˜ ๊ฐ์ฒด
    const [value, setValue] = useState(0);
    return <button onClick={() => setValue(v => v + 1)}>{value}</button>;
  };
 
  return <ChildComponent />; // ์ƒํƒœ๊ฐ€ ๋งค๋ฒˆ ๋ฆฌ์…‹๋จ ๐Ÿ’ฃ
}
 
// โœ… ๋ฐ”๊นฅ์œผ๋กœ ๊บผ๋‚ด๊ธฐ
const ChildComponent = () => {  // ํ•œ ๋ฒˆ๋งŒ ์ƒ์„ฑ๋จ
  const [value, setValue] = useState(0);
  return <button onClick={() => setValue(v => v + 1)}>{value}</button>;
};
 
function ParentComponent() {
  return <ChildComponent />; // ํ•ญ์ƒ ๊ฐ™์€ ์ฐธ์กฐ โ†’ ์ƒํƒœ ์œ ์ง€ โœ…
}

๐Ÿ’ก ํ•œ ์ค„๋กœ ๊ธฐ์–ตํ•˜๊ธฐ
์ปดํฌ๋„ŒํŠธ๋Š” ๋ชจ๋“ˆ์˜ ์ตœ์ƒ์œ„ ๋ ˆ๋ฒจ์—๋งŒ ์ •์˜ํ•ด์š”. ๋ Œ๋” ํ•จ์ˆ˜ ์•ˆ์— ์ปดํฌ๋„ŒํŠธ๋ฅผ ์“ฐ๋ฉด ๋งค ๋ Œ๋”๋งˆ๋‹ค "์ƒˆ ์ฃผ๋ฏผ๋“ฑ๋ก๋ฒˆํ˜ธ" ๋ฅผ ๋ฐœ๊ธ‰๋ฐ›์•„์„œ ์ƒํƒœ๊ฐ€ ํญ๋ฐœํ•ด์š”.


๐Ÿ’ฅ ์—๋Ÿฌ ํ•ด๊ฒฐ ์นดํƒˆ๋กœ๊ทธ

์—๋Ÿฌ๋‚˜ ์ด์ƒํ•œ ๋™์ž‘์ด ๋ฐœ์ƒํ•˜๋ฉด Ctrl+F ๋กœ ์ฆ์ƒ์˜ ํ‚ค์›Œ๋“œ๋ฅผ ๊ฒ€์ƒ‰ํ•ด๋ด์š”. ๋Œ€๋ถ€๋ถ„ ์—ฌ๊ธฐ ์žˆ์–ด์š”.


โŒ ์ฆ์ƒ: ์ž…๋ ฅ์ฐฝ์— ๊ธ€์ž๋ฅผ ์น˜๋ฉด ํฌ์ปค์Šค๊ฐ€ ์‚ฌ๋ผ์ง€๊ฑฐ๋‚˜ ์ž…๋ ฅํ•œ ๋‚ด์šฉ์ด ์ฆ‰์‹œ ์ง€์›Œ์ง„๋‹ค

์–ธ์ œ ๋‚˜์˜ค๋Š”๊ฐ€?

์ž…๋ ฅ์ฐฝ์„ ํด๋ฆญํ•ด์„œ 'ใ……' ์„ ์ž…๋ ฅํ•˜๋ฉด ํฌ์ปค์Šค๊ฐ€ ์‚ฌ๋ผ์ง€๊ฑฐ๋‚˜
์ž…๋ ฅ ํ›„ ์ปดํฌ๋„ŒํŠธ๊ฐ€ unmount/remount ๋˜๋Š” ๊ฒƒ์ฒ˜๋Ÿผ ๋ณด์ž„

์›์ธ: ๋ Œ๋” ํ•จ์ˆ˜ ์•ˆ์— ์ž…๋ ฅ ์ปดํฌ๋„ŒํŠธ๋ฅผ ์ •์˜ํ•ด์„œ ๋งค ๋ Œ๋”๋งˆ๋‹ค ์ƒˆ ์ปดํฌ๋„ŒํŠธ ํƒ€์ž…์œผ๋กœ ๊ต์ฒด๋˜๋Š” ์ƒํ™ฉ

์ง„๋‹จ ์ฝ”๋“œ:

// ์ด๋Ÿฐ ํŒจํ„ด์ด ์žˆ์œผ๋ฉด ๋ฒ”์ธ
function ParentComponent() {
  // โš ๏ธ ๋ Œ๋” ์•ˆ์— ์ปดํฌ๋„ŒํŠธ ์ •์˜ ๋ฐœ๊ฒฌ!
  function InputField() {
    const [text, setText] = useState('');
    return <input value={text} onChange={e => setText(e.target.value)} />;
  }
  return <InputField />;  // ๋งค ๋ Œ๋”๋งˆ๋‹ค ๋ฆฌ์…‹๋จ
}

ํ•ด๊ฒฐ์ฑ…:

// InputField๋ฅผ ํŒŒ์ผ ์ตœ์ƒ์œ„๋กœ ๊บผ๋‚ด๊ธฐ
function InputField() {
  const [text, setText] = useState('');
  return <input value={text} onChange={e => setText(e.target.value)} />;
}
 
function ParentComponent() {
  return <InputField />;  // ์ด์ œ ์•ˆ์ •์ ์œผ๋กœ ์ž‘๋™
}

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


โŒ ์ฆ์ƒ: ํ”Œ๋ ˆ์ด์–ด/์œ ์ €๋ฅผ ์ „ํ™˜ํ–ˆ๋Š”๋ฐ ์ด์ „ ์‚ฌ๋žŒ์˜ ์ƒํƒœ(์ ์ˆ˜, ์ž…๋ ฅ๊ฐ’ ๋“ฑ)๊ฐ€ ๋‚จ์•„์žˆ๋‹ค

์›์ธ: ๊ฐ™์€ ์œ„์น˜์— ๊ฐ™์€ ์ปดํฌ๋„ŒํŠธ ํƒ€์ž…์„ ์กฐ๊ฑด๋ถ€๋กœ ๋ Œ๋”๋งํ•˜๊ณ  ์žˆ์–ด์„œ React ๊ฐ€ ๋™์ผ ์ธ์Šคํ„ด์Šค๋กœ ์ธ์‹

์ง„๋‹จ ์ฝ”๋“œ:

// ์ด๋Ÿฐ ํŒจํ„ด์ด ์žˆ์œผ๋ฉด ๋ฒ”์ธ
{isPlayerA ? <Counter person="์˜ํ˜ธ" /> : <Counter person="์˜์ฒ " />}
// ๊ฐ™์€ ์œ„์น˜, ๊ฐ™์€ ํƒ€์ž… โ†’ ์ƒํƒœ ์œ ์ง€๋จ

ํ•ด๊ฒฐ์ฑ…:

// key๋ฅผ ์ถ”๊ฐ€ํ•ด์„œ ์ธ์Šคํ„ด์Šค ๋ช…์‹œ์  ๋ถ„๋ฆฌ
{isPlayerA
  ? <Counter key="์˜ํ˜ธ" person="์˜ํ˜ธ" />
  : <Counter key="์˜์ฒ " person="์˜์ฒ " />
}

โŒ ์ฆ์ƒ: ํผ ์ œ์ถœ ํ›„ ์ž…๋ ฅ ํ•„๋“œ๊ฐ€ ๋น„์›Œ์ง€์ง€ ์•Š๋Š”๋‹ค

์›์ธ: ํผ ์ œ์ถœ ํ›„ ์ƒํƒœ๋ฅผ ์ˆ˜๋™์œผ๋กœ ๋ฆฌ์…‹ํ•˜์ง€ ์•Š๊ฑฐ๋‚˜, ์ปดํฌ๋„ŒํŠธ๊ฐ€ ๋™์ผ ์ธ์Šคํ„ด์Šค๋กœ ์œ ์ง€๋˜๋Š” ์ƒํ™ฉ

ํ•ด๊ฒฐ์ฑ… A: key ํŠธ๋ฆญ (์ƒํƒœ๊ฐ€ ๋งŽ์„ ๋•Œ ์ถ”์ฒœ):

function Parent() {
  const [formKey, setFormKey] = useState(0);
 
  const handleSubmit = async (data) => {
    await submitData(data);
    setFormKey(prev => prev + 1); // key ๋ณ€๊ฒฝ โ†’ ํผ ์ „์ฒด ๋ฆฌ์…‹
  };
 
  return <MyForm key={formKey} onSubmit={handleSubmit} />;
}

ํ•ด๊ฒฐ์ฑ… B: ์ˆ˜๋™ ๋ฆฌ์…‹ (์ƒํƒœ๊ฐ€ 1-2๊ฐœ์ผ ๋•Œ):

function MyForm({ onSubmit }) {
  const [value, setValue] = useState('');
 
  const handleSubmit = async () => {
    await onSubmit(value);
    setValue(''); // ์ œ์ถœ ํ›„ ์ˆ˜๋™ ๋ฆฌ์…‹
  };
 
  return <input value={value} onChange={e => setValue(e.target.value)} />;
}

โŒ ์ฆ์ƒ: ์—ฐ๋ฝ์ฒ˜๋ฅผ ์ „ํ™˜ํ–ˆ๋Š”๋ฐ ์ด์ „ ๋Œ€ํ™”์˜ ๋ฏธ์ „์†ก ๋ฉ”์‹œ์ง€๊ฐ€ ๋‚จ์•„์žˆ๋‹ค

์›์ธ: ChatWindow ๊ฐ™์€ ์ปดํฌ๋„ŒํŠธ์— key ๋ฅผ ์ฃผ์ง€ ์•Š์•„์„œ ๊ฐ™์€ ์ธ์Šคํ„ด์Šค๋ฅผ ์žฌ์‚ฌ์šฉํ•˜๊ณ  ์žˆ์Œ

ํ•ด๊ฒฐ์ฑ…:

<ChatWindow
  key={selectedContact}  // ์—ฐ๋ฝ์ฒ˜๊ฐ€ ๋ฐ”๋€Œ๋ฉด ์ƒˆ ์ธ์Šคํ„ด์Šค
  contact={selectedContact}
/>

โŒ ๊ฒฝ๊ณ : Warning: Each child in a list should have a unique "key" prop.

์–ธ์ œ ๋‚˜์˜ค๋Š”๊ฐ€?

Warning: Each child in a list should have a unique "key" prop.
  at li
  at PostItem

์›์ธ: .map() ์œผ๋กœ ๋ชฉ๋ก์„ ๋ Œ๋”๋งํ•  ๋•Œ key prop ์„ ๋ˆ„๋ฝํ•˜๊ฑฐ๋‚˜ ์ค‘๋ณต๋œ key ๋ฅผ ์‚ฌ์šฉ

์ ˆ๋Œ€ ํ•˜๋ฉด ์•ˆ ๋˜๋Š” ๊ฒƒ:

// โŒ key ์—†์Œ
posts.map(post => <PostItem post={post} />)
 
// โŒ index๋ฅผ key๋กœ ์‚ฌ์šฉ (๋ชฉ๋ก ์ˆœ์„œ๊ฐ€ ๋ฐ”๋€” ์ˆ˜ ์žˆ๋Š” ๊ฒฝ์šฐ)
posts.map((post, index) => <PostItem key={index} post={post} />)
// ์ •๋ ฌ, ์ถ”๊ฐ€, ์‚ญ์ œ๊ฐ€ ์ผ์–ด๋‚˜๋ฉด key-์ธ์Šคํ„ด์Šค ๋งคํ•‘์ด ์—‰ํ‚ด
 
// โŒ ์ค‘๋ณต key
posts.map(post => <PostItem key="item" post={post} />)

์˜ฌ๋ฐ”๋ฅธ ํ•ด๊ฒฐ์ฑ…:

// โœ… ๊ณ ์œ ํ•˜๊ณ  ์•ˆ์ •์ ์ธ ID ์‚ฌ์šฉ
posts.map(post => <PostItem key={post.id} post={post} />)
 
// โœ… index๋Š” ๋ชฉ๋ก์ด ์ ˆ๋Œ€ ๋ณ€ํ•˜์ง€ ์•Š์„ ๋•Œ๋งŒ ํ—ˆ์šฉ
staticItems.map((item, index) => <Item key={index} item={item} />)

๐Ÿ ์ด๋ฒˆ์— ๋ฐฐ์šด ๋‚ด์šฉ ์ด์ •๋ฆฌ

์˜ค๋Š˜ ๋ฐฐ์šด ํ•ต์‹ฌ์„ ํ•œ๋ˆˆ์— ์ •๋ฆฌํ•ด๋ด์š”. ์‹ค๋ฌด์—์„œ ๊ธธ์„ ์žƒ์—ˆ์„ ๋•Œ ์ด๊ฒƒ๋งŒ ๋ด๋„ ๋ผ์š”.

๐Ÿ“‹ ํ•ต์‹ฌ ์›๋ฆฌ ์š”์•ฝ

์›๋ฆฌ๋‚ด์šฉ๊ธฐ์–ต๋ฒ•
์ƒํƒœ ๋ณด๊ด€ ์œ„์น˜์ปดํฌ๋„ŒํŠธ ํ•จ์ˆ˜ ์•ˆ์ด ์•„๋‹Œ, React ๊ฐ€ ๊ด€๋ฆฌํ•˜๋Š” ๋ Œ๋” ํŠธ๋ฆฌ์˜ ์œ„์น˜์— ๋ณด๊ด€"์ขŒ์„ ๋ฒˆํ˜ธ์— ๋ถ™์€ ํฌ์ŠคํŠธ์ž‡"
๊ฐ™์€ ์œ„์น˜ + ๊ฐ™์€ ํƒ€์ž…์ƒํƒœ ๋ณด์กด, prop ๋งŒ ์—…๋ฐ์ดํŠธ"๊ฐ™์€ ์ž๋ฆฌ, ๊ฐ™์€ ์˜์ž โ†’ ํฌ์ŠคํŠธ์ž‡ ์œ ์ง€"
๊ฐ™์€ ์œ„์น˜ + ๋‹ค๋ฅธ ํƒ€์ž…๊ธฐ์กด ํŠธ๋ฆฌ ์–ธ๋งˆ์šดํŠธ + ์ƒˆ ๋งˆ์šดํŠธ โ†’ ์ƒํƒœ ์ดˆ๊ธฐํ™”"์˜์ž ์ข…๋ฅ˜๊ฐ€ ๋ฐ”๋€Œ๋ฉด ํฌ์ŠคํŠธ์ž‡ ์ƒˆ๋กœ ๋ถ™์ž„"
key ์—ญํ• ๊ฐ™์€ ํƒ€์ž…์ด๋ผ๋„ ๋‹ค๋ฅธ ์ธ์Šคํ„ด์Šค์ž„์„ ๋ช…์‹œ โ†’ ์ƒํƒœ ๊ฐ•์ œ ๋ฆฌ์…‹"์ฃผ๋ฏผ๋“ฑ๋ก๋ฒˆํ˜ธ ๊ต์ฒด"
์–ธ๋งˆ์šดํŠธํŠธ๋ฆฌ์—์„œ ์ œ๊ฑฐ๋  ๋•Œ ํ•ด๋‹น ์œ„์น˜์˜ ์ƒํƒœ๋„ ํ•จ๊ป˜ ์‚ญ์ œ"์ž๋ฆฌ ์—†์• ๋ฉด ํฌ์ŠคํŠธ์ž‡๋„ ๋ฒ„๋ฆผ"

๐ŸŽฏ key ์‚ฌ์šฉ ํŒจํ„ด ์น˜ํŠธ์‹œํŠธ

์ƒํ™ฉkey ๊ฐ’ํšจ๊ณผ
ํ”Œ๋ ˆ์ด์–ด/์œ ์ € ์ „ํ™˜ ์‹œ ์ƒํƒœ ๋ฆฌ์…‹key={userId}์œ ์ € ๋ฐ”๋€Œ๋ฉด ์ƒˆ ์ธ์Šคํ„ด์Šค
ํผ ์ œ์ถœ ํ›„ ๊ฐ•์ œ ์ดˆ๊ธฐํ™”key={submitCount}์ œ์ถœ ์‹œ ์นด์šดํ„ฐ ์ฆ๊ฐ€ โ†’ ์ƒˆ ๋งˆ์šดํŠธ
์—ฐ๋ฝ์ฒ˜๋ณ„ ์ฑ„ํŒ…์ฐฝ ๋ถ„๋ฆฌkey={contactId}์—ฐ๋ฝ์ฒ˜ ๋ฐ”๋€Œ๋ฉด ์ƒˆ ์ฑ„ํŒ…์ฐฝ
๊ฒ€์ƒ‰์–ด๋ณ„ ๊ฒฐ๊ณผ ๋ถ„๋ฆฌkey={searchQuery}๊ฒ€์ƒ‰์–ด ๋ฐ”๋€Œ๋ฉด ๊ฒฐ๊ณผ ๋ฆฌ์…‹
ํฌ์ŠคํŠธ๋ณ„ ์—๋””ํ„ฐ ๋ถ„๋ฆฌkey={postId}ํฌ์ŠคํŠธ ๋ฐ”๋€Œ๋ฉด ์—๋””ํ„ฐ ์ดˆ๊ธฐํ™”
๋ชฉ๋ก ์•„์ดํ…œkey={item.id}์ •๋ ฌ/์‚ญ์ œ ์‹œ ์ƒํƒœ ์•ˆ์ „ ์œ ์ง€

โš ๏ธ ์ ˆ๋Œ€ ํ•˜์ง€ ๋ง ๊ฒƒ

์ƒํ™ฉโŒ ๋‚˜์œ ์˜ˆโœ… ์ข‹์€ ์˜ˆ์ด์œ 
์ปดํฌ๋„ŒํŠธ ์ •์˜ ์œ„์น˜๋ Œ๋” ํ•จ์ˆ˜ ์•ˆ์— ์ •์˜๋ชจ๋“ˆ ์ตœ์ƒ์œ„์— ์ •์˜๋งค ๋ Œ๋”๋งˆ๋‹ค ์ƒˆ ํƒ€์ž… โ†’ ์ƒํƒœ ํญ๋ฐœ
๋ชฉ๋ก key ์„ ํƒkey={index} (๊ฐ€๋ณ€ ๋ชฉ๋ก)key={item.id}์ˆœ์„œ ๋ณ€๊ฒฝ ์‹œ ์ƒํƒœ ์—‰ํ‚ด
์ƒํƒœ ๋ฆฌ์…‹ ๋ฐฉ๋ฒ•์กฐ๊ฑด๋ถ€๋กœ ๋‹ค๋ฅธ ๋ž˜ํผ ํƒœ๊ทธ ์‚ฌ์šฉkey ๋ณ€๊ฒฝ์ฝ”๋“œ ๊ฐ€๋…์„ฑ ์ €ํ•˜
ํƒ€์ž… ๋น„๊ต ์˜คํ•ดprop ์ด ๋‹ค๋ฅด๋ฉด ๋‹ค๋ฅธ ์ปดํฌ๋„ŒํŠธํƒ€์ž…๊ณผ ์œ„์น˜๊ฐ€ ๊ฐ™์œผ๋ฉด ๋™์ผ์ƒํƒœ ์œ ์ง€ ๋ฒ„๊ทธ ๋ฐœ์ƒ

๐Ÿ”„ ์ƒํƒœ ๋ณด์กด vs ๋ฆฌ์…‹ ๊ฒฐ์ • ํŠธ๋ฆฌ

์ปดํฌ๋„ŒํŠธ๊ฐ€ ๋ Œ๋”๋ง๋  ๋•Œ:
โ”œโ”€โ”€ ์ด์ „ ๋ Œ๋”์™€ ๊ฐ™์€ ์œ„์น˜?
โ”‚   โ”œโ”€โ”€ NO โ†’ ์ƒˆ ๋งˆ์šดํŠธ (์ด์ „ ์ƒํƒœ ์‚ญ์ œ)
โ”‚   โ””โ”€โ”€ YES โ†’ ๊ณ„์† ๋น„๊ต...
โ”‚       โ”œโ”€โ”€ key๊ฐ€ ๊ฐ™์€๊ฐ€?
โ”‚       โ”‚   โ”œโ”€โ”€ NO โ†’ ์–ธ๋งˆ์šดํŠธ ํ›„ ์ƒˆ ๋งˆ์šดํŠธ (์ƒํƒœ ๋ฆฌ์…‹)
โ”‚       โ”‚   โ””โ”€โ”€ YES โ†’ ๊ณ„์† ๋น„๊ต...
โ”‚       โ”‚       โ”œโ”€โ”€ ์ปดํฌ๋„ŒํŠธ ํƒ€์ž…์ด ๊ฐ™์€๊ฐ€?
โ”‚       โ”‚       โ”‚   โ”œโ”€โ”€ NO โ†’ ์–ธ๋งˆ์šดํŠธ ํ›„ ์ƒˆ ๋งˆ์šดํŠธ (์ƒํƒœ ๋ฆฌ์…‹)
โ”‚       โ”‚       โ”‚   โ””โ”€โ”€ YES โ†’ ๊ธฐ์กด ์ธ์Šคํ„ด์Šค ์žฌ์‚ฌ์šฉ (์ƒํƒœ ๋ณด์กด) + prop ์—…๋ฐ์ดํŠธ

๐Ÿฃ ์˜์ฒ ์ด์˜ ํ‡ด๊ทผ ์ผ๊ธฐ

์˜ค๋ฅ˜ ์—†์ด ์ž˜ ๋Œ์•„๊ฐ€๋˜ ์ปดํฌ๋„ŒํŠธ์—์„œ ๊ฐ‘์ž๊ธฐ ํฌ์ปค์Šค๊ฐ€ ๋‚ ์•„๊ฐ€๊ณ  ์ƒํƒœ๊ฐ€ ์ฆ๋ฐœํ–ˆ๋˜ ๋ฏธ์Šคํ„ฐ๋ฆฌ๊ฐ€ ๋ Œ๋” ํŠธ๋ฆฌ ๊ฐœ๋… ํ•˜๋‚˜๋กœ ๋ปฅ ๋šซ๋ ธ๋‹ค. ๋‚ด๊ฐ€ ์ปดํฌ๋„ŒํŠธ ์•ˆ์— ์ปดํฌ๋„ŒํŠธ๋ฅผ ์ •์˜ํ•˜๋Š” ๋”์ฐํ•œ ์ง“์„ ํ•˜๊ณ  ์žˆ์—ˆ๋‹ค๋‹ˆ!

๐Ÿ’ก "์ƒํƒœ๋Š” ์ปดํฌ๋„ŒํŠธ ์•ˆ์— ์žˆ๋Š” ๊ฒŒ ์•„๋‹ˆ๋ผ, ํŠธ๋ฆฌ์˜ '์œ„์น˜'์— ์„ธ๋“ค์–ด ์‚ฌ๋Š” ๊ฑฐ๋‹ค. Key๋Š” ๊ทธ ์„ธ์ž…์ž์˜ ์ „์ž…์‹ ๊ณ (์ฃผ๋ฏผ๋“ฑ๋ก๋ฒˆํ˜ธ)์™€ ๊ฐ™๋‹ค!"

๋‹จ์ˆœํžˆ ๋ฆฌ์ŠคํŠธ ๊ฒฝ๊ณ  ์ง€์šฐ๋ ค๊ณ  ๋Œ€์ถฉ ๋„ฃ๋˜ key={index}๊ฐ€ ์–ผ๋งˆ๋‚˜ ์œ„ํ—˜ํ•œ ์‹œํ•œํญํƒ„์ธ์ง€ ์•Œ์•˜๋‹ค. ํผ ์ƒํƒœ๋ฅผ ๋‚ ๋ ค๋ฒ„๋ฆด ๋•Œ๋‚˜, ์ฑ„ํŒ…์ฐฝ์„ ์™„์ „ํžˆ ๊ต์ฒดํ•  ๋•Œ key ํŠธ๋ฆญ์„ ์“ฐ๋Š” ๊ฑธ ์•Œ๊ณ  ๋‚˜๋‹ˆ, ๋ญ”๊ฐ€ ๋ฆฌ์•กํŠธ ์—”์ง„์˜ ๋ฉฑ์‚ด์„ ์žก๊ณ  ์กฐ์ข…ํ•˜๋Š” ๋А๋‚Œ์ด ๋“ค์–ด ๋ฌ˜ํ•˜๊ฒŒ ์พŒ๊ฐ์ด ์ธ๋‹ค.


๐Ÿ“ ๋งˆ๋ฌด๋ฆฌ ํ€ด์ฆˆ

Q1. ์ƒํƒœ ๋ณด์กด ์—ฌ๋ถ€ ํŒ๋‹จ ๐ŸŸข

Q1. ์•„๋ž˜ ์ฝ”๋“œ์—์„œ isAdmin ์ด true โ†’ false ๋กœ ๋ฐ”๋€Œ๋ฉด UserPanel ์˜ ์ƒํƒœ๋Š” ์–ด๋–ป๊ฒŒ ๋ ๊นŒ์š”?

function App() {
  const [isAdmin, setIsAdmin] = useState(true);
  return (
    <div>
      {isAdmin ? <UserPanel role="admin" /> : <UserPanel role="viewer" />}
    </div>
  );
}
  • A) ์ƒํƒœ๊ฐ€ ์™„์ „ํžˆ ๋ฆฌ์…‹๋œ๋‹ค. role prop ์ด ๋‹ฌ๋ผ์กŒ๊ธฐ ๋•Œ๋ฌธ์ด๋‹ค.
  • B) ์ƒํƒœ๊ฐ€ ์œ ์ง€๋œ๋‹ค. ๊ฐ™์€ ์œ„์น˜์— ๊ฐ™์€ ํƒ€์ž…(UserPanel) ์ด๊ธฐ ๋•Œ๋ฌธ์ด๋‹ค.
  • C) ์ƒํƒœ๊ฐ€ ์œ ์ง€๋œ๋‹ค. React ๋Š” ํ•ญ์ƒ ์ƒํƒœ๋ฅผ ๋ณด์กดํ•œ๋‹ค.
  • D) ์ƒํƒœ๊ฐ€ ๋ฆฌ์…‹๋œ๋‹ค. ์กฐ๊ฑด๋ถ€ ๋ Œ๋”๋ง์€ ํ•ญ์ƒ ์–ธ๋งˆ์šดํŠธ๋ฅผ ์œ ๋ฐœํ•œ๋‹ค.

โœ… ์ •๋‹ต: B โ€” ๊ฐ™์€ ์œ„์น˜์— ๊ฐ™์€ ํƒ€์ž…์ด ์˜ค๋ฉด prop ๋‚ด์šฉ์— ์ƒ๊ด€์—†์ด ์ƒํƒœ๋ฅผ ๋ณด์กดํ•ด์š”.

์˜ค๋‹ต ํ•ด์„ค:

  • A โ€” React ๋Š” prop ์˜ ๋‚ด์šฉ์ด ์•„๋‹ˆ๋ผ ์ปดํฌ๋„ŒํŠธ ํƒ€์ž…๊ณผ ํŠธ๋ฆฌ ์œ„์น˜๋ฅผ ๋ด์š”. role ์ด ๋‹ฌ๋ผ์ ธ๋„ ํƒ€์ž…์ด ๊ฐ™์œผ๋ฉด ์—…๋ฐ์ดํŠธ๋กœ ์ฒ˜๋ฆฌํ•ด์š”.
  • C โ€” React ๊ฐ€ ํ•ญ์ƒ ์ƒํƒœ๋ฅผ ๋ณด์กดํ•˜๋Š” ๊ฑด ์•„๋‹ˆ์—์š”. ํƒ€์ž…์ด ๋‹ฌ๋ผ์ง€๊ฑฐ๋‚˜ key ๊ฐ€ ๋‹ฌ๋ผ์ง€๋ฉด ๋ฆฌ์…‹๋ผ์š”.
  • D โ€” ์กฐ๊ฑด๋ถ€ ๋ Œ๋”๋ง ์ž์ฒด๊ฐ€ ์–ธ๋งˆ์šดํŠธ๋ฅผ ์œ ๋ฐœํ•˜๋Š” ๊ฒŒ ์•„๋‹ˆ์—์š”. ์กฐ๊ฑด์ด ๋ฐ”๋€Œ์–ด๋„ ๊ฐ™์€ ์œ„์น˜์— ๊ฐ™์€ ํƒ€์ž…์ด ์˜ค๋ฉด ์žฌ์‚ฌ์šฉํ•ด์š”.

๐Ÿ“Œ ํ•ต์‹ฌ ๊ธฐ์–ต๋ฒ•: React ๋Š” "ํƒ€์ž… + ์œ„์น˜ + key" ๊ฐ€ ๋ชจ๋‘ ๊ฐ™์•„์•ผ ๋™์ผ ์ธ์Šคํ„ด์Šค๋กœ ์ธ์‹ํ•ด์š”. prop ์€ ํŒ๋ณ„ ๊ธฐ์ค€์ด ์•„๋‹ˆ์—์š”.


Q2. ๋นˆ์นธ ์ฑ„์šฐ๊ธฐ ๐ŸŸก

Q2. ์˜์ˆ˜๋„ค ์ปค๋ฎค๋‹ˆํ‹ฐ ์ฑ„ํŒ… ๊ธฐ๋Šฅ์—์„œ ์—ฐ๋ฝ์ฒ˜๋ฅผ ๋ฐ”๊ฟ€ ๋•Œ๋งˆ๋‹ค ์ฑ„ํŒ…์ฐฝ์„ ์™„์ „ํžˆ ์ดˆ๊ธฐํ™”ํ•˜๊ณ  ์‹ถ์–ด์š”. ๋นˆ์นธ์„ ์ฑ„์›Œ๋ณด์„ธ์š”.

function ChatPage() {
  const [activeContact, setActiveContact] = useState('์˜ํ˜ธ');
 
  return (
    <ChatWindow
      _______________    // ์—ฌ๊ธฐ์— ๋ฌด์—‡์„ ์จ์•ผ ํ• ๊นŒ์š”?
      contact={activeContact}
    />
  );
}

โœ… ์ •๋‹ต: key={activeContact}

ํ•ด์„ค: key={activeContact} ๋ฅผ ์ถ”๊ฐ€ํ•˜๋ฉด activeContact ๊ฐ€ '์˜ํ˜ธ' ์—์„œ '์˜์ฒ ' ๋กœ ๋ฐ”๋€” ๋•Œ key ๊ฐ’์ด ๋‹ฌ๋ผ์ง€๊ณ , React ๋Š” ์ด๋ฅผ ์™„์ „ํžˆ ์ƒˆ ์ปดํฌ๋„ŒํŠธ๋กœ ์ธ์‹ํ•ด์„œ ์–ธ๋งˆ์šดํŠธ ํ›„ ์ƒˆ๋กœ ๋งˆ์šดํŠธํ•ด์š”. ChatWindow ๋‚ด๋ถ€์˜ ๋ชจ๋“  ์ƒํƒœ(์ž…๋ ฅ ์ค‘์ธ ๋ฉ”์‹œ์ง€, ์Šคํฌ๋กค ์œ„์น˜ ๋“ฑ) ๊ฐ€ ์ดˆ๊ธฐํ™”๋ผ์š”.

๐Ÿ“Œ ํ•ต์‹ฌ ๊ธฐ์–ต๋ฒ•: "์—ฐ๋ฝ์ฒ˜ = key" ํŒจํ„ด์ด์—์š”. ์—ฐ๋ฝ์ฒ˜๋งˆ๋‹ค ๋…๋ฆฝ๋œ ์ฑ„ํŒ…์ฐฝ ์ธ์Šคํ„ด์Šค๋ฅผ ์›ํ•œ๋‹ค๋ฉด ์—ฐ๋ฝ์ฒ˜ ID ๋ฅผ key ๋กœ ์ฃผ๋ฉด ๋ผ์š”.


Q3. ๋””๋ฒ„๊น… ํ€ด์ฆˆ ๐Ÿ”ด

Q3. ์•„๋ž˜ ์ฝ”๋“œ์—์„œ StudyFilter ๋‚ด๋ถ€์˜ ํ•„ํ„ฐ ์ƒํƒœ๊ฐ€ ์ž…๋ ฅํ•  ๋•Œ๋งˆ๋‹ค ๋ฆฌ์…‹๋˜๋Š” ๋ฒ„๊ทธ๊ฐ€ ์žˆ์–ด์š”. ๋ฌธ์ œ๋ฅผ ์ฐพ์•„๋ณด์„ธ์š”.

function StudySearchPage() {
  const [keyword, setKeyword] = useState('');
  const [results, setResults] = useState([]);
 
  // (A) ๋งค ๋ Œ๋”๋งˆ๋‹ค ์ƒˆ๋กœ ์ƒ์„ฑ๋˜๋Š” ์ปดํฌ๋„ŒํŠธ
  const StudyFilter = () => {
    const [selectedCategory, setSelectedCategory] = useState('all');
    const [sortOrder, setSortOrder] = useState('latest');
 
    return (
      <div>
        <select value={selectedCategory} onChange={e => setSelectedCategory(e.target.value)}>
          <option value="all">์ „์ฒด</option>
          <option value="frontend">ํ”„๋ก ํŠธ์—”๋“œ</option>
        </select>
        <select value={sortOrder} onChange={e => setSortOrder(e.target.value)}>
          <option value="latest">์ตœ์‹ ์ˆœ</option>
          <option value="popular">์ธ๊ธฐ์ˆœ</option>
        </select>
      </div>
    );
  };
 
  return (
    <div>
      <input
        value={keyword}
        onChange={e => setKeyword(e.target.value)}  // (B) ์ž…๋ ฅ ์‹œ StudySearchPage ๋ฆฌ๋ Œ๋”๋ง
      />
      <StudyFilter />  {/* (C) ๋ฆฌ๋ Œ๋”๋ง๋  ๋•Œ๋งˆ๋‹ค ์ƒˆ ํƒ€์ž…์œผ๋กœ ์ธ์‹๋จ */}
      <SearchResults results={results} />
    </div>
  );
}

์ด ์ฝ”๋“œ์˜ ๋ฌธ์ œ์ ์€? (ํ•ด๋‹นํ•˜๋Š” ๊ฒƒ ๋ชจ๋‘ ์„ ํƒ)

  • A) (A) ์—์„œ const StudyFilter = () => ์ฒ˜๋Ÿผ ํ™”์‚ดํ‘œ ํ•จ์ˆ˜๋กœ ์ •์˜ํ•ด์„œ ๋ฌธ์ œ๋‹ค.
  • B) (B) ์—์„œ setKeyword ๋ฅผ ํ˜ธ์ถœํ•˜๋ฉด StudySearchPage ๊ฐ€ ๋ฆฌ๋ Œ๋”๋ง๋˜๊ณ , ๊ทธ๋Ÿฌ๋ฉด (A) ์—์„œ ์ƒˆ StudyFilter ํ•จ์ˆ˜ ๊ฐ์ฒด๊ฐ€ ๋งŒ๋“ค์–ด์ง„๋‹ค.
  • C) (C) ์—์„œ <StudyFilter /> ๋Š” ๋ Œ๋”๋งˆ๋‹ค ์ƒˆ ํƒ€์ž…์œผ๋กœ ์ธ์‹๋˜์–ด ์–ธ๋งˆ์šดํŠธ + ์ƒˆ ๋งˆ์šดํŠธ๋œ๋‹ค.
  • D) results ์ƒํƒœ๊ฐ€ ๋น„์–ด์žˆ์–ด์„œ ๋ฌธ์ œ๋‹ค.

โœ… ์ •๋‹ต: B, C

์˜ค๋‹ต ํ•ด์„ค:

  • A โ€” ํ™”์‚ดํ‘œ ํ•จ์ˆ˜ ์ž์ฒด๊ฐ€ ๋ฌธ์ œ๊ฐ€ ์•„๋‹ˆ์—์š”. ๋ Œ๋” ํ•จ์ˆ˜ "์•ˆ์— ์ •์˜๋œ๋‹ค๋Š” ๊ฒƒ" ์ด ๋ฌธ์ œ์˜ˆ์š”. function StudyFilter() ๋กœ ๋ฐ”๊ฟ”๋„ ๋ Œ๋” ํ•จ์ˆ˜ ์•ˆ์— ์žˆ์œผ๋ฉด ๋™์ผํ•˜๊ฒŒ ๋ง๊ฐ€์ ธ์š”.
  • D โ€” results ์ƒํƒœ๋Š” ํ•„ํ„ฐ ์ƒํƒœ ๋ฆฌ์…‹๊ณผ ๋ฌด๊ด€ํ•ด์š”.

์˜ฌ๋ฐ”๋ฅธ ํ•ด๊ฒฐ์ฑ…:

// StudyFilter๋ฅผ ํŒŒ์ผ ์ตœ์ƒ์œ„๋กœ ๊บผ๋ƒ„
const StudyFilter = () => {
  const [selectedCategory, setSelectedCategory] = useState('all');
  const [sortOrder, setSortOrder] = useState('latest');
  // ...
};
 
function StudySearchPage() {
  const [keyword, setKeyword] = useState('');
  // StudyFilter๋Š” ์ด์ œ ์•ˆ์ •์ ์ธ ์ฐธ์กฐ โ†’ ํ•„ํ„ฐ ์ƒํƒœ ์œ ์ง€๋จ
  return (
    <div>
      <input value={keyword} onChange={e => setKeyword(e.target.value)} />
      <StudyFilter />
    </div>
  );
}

๐Ÿ“Œ ํ•ต์‹ฌ ๊ธฐ์–ต๋ฒ•: ๋ Œ๋” ํ•จ์ˆ˜ ์•ˆ์— ์ •์˜๋œ ์ปดํฌ๋„ŒํŠธ๋Š” ๋งค ๋ Œ๋”๋งˆ๋‹ค ์ƒˆ ์ฃผ๋ฏผ๋“ฑ๋ก๋ฒˆํ˜ธ๋ฅผ ๋ฐ›์•„์š”. ์ปดํฌ๋„ŒํŠธ๋Š” ๋ฐ˜๋“œ์‹œ ๋ชจ๋“ˆ ์ตœ์ƒ์œ„์— ์ •์˜ํ•˜์„ธ์š”.


Q4. ์นœ๊ตฌ์—๊ฒŒ ์„ค๋ช…ํ•œ๋‹ค๋ฉด? ๐ŸŸข

Q4. "React ์—์„œ key ๊ฐ€ ๋ญ์•ผ?" ๋ผ๋Š” ์งˆ๋ฌธ์„ ๋ฐ›์•˜์–ด์š”. ๋น„์œ ๋ฅผ ์จ์„œ ํ•œ ๋ฌธ์žฅ์œผ๋กœ ์„ค๋ช…ํ•ด๋ด์š”.

(์ •๋‹ต์€ ์—†์–ด์š”. ๋ณธ์ธ๋งŒ์˜ ๋น„์œ ๋กœ ์„ค๋ช…ํ•  ์ˆ˜ ์žˆ์œผ๋ฉด ์ถฉ๋ถ„ํ•ด์š”.)

์˜ˆ์‹œ ๋‹ต๋ณ€๋“ค:

"key ๋Š” ์ปดํฌ๋„ŒํŠธ์˜ ์ฃผ๋ฏผ๋“ฑ๋ก๋ฒˆํ˜ธ์•ผ. ๋ฒˆํ˜ธ๊ฐ€ ๋ฐ”๋€Œ๋ฉด React ๋Š” ์ƒˆ ์‚ฌ๋žŒ์ด ์˜จ ๊ฒƒ์ฒ˜๋Ÿผ ์ƒํƒœ๋ฅผ ๋ฆฌ์…‹ํ•˜๊ณ , ๋ฒˆํ˜ธ๊ฐ€ ๊ฐ™์œผ๋ฉด ์ด์‚ฌ๋ฅผ ๊ฐ€๋„ ๊ฐ™์€ ์‚ฌ๋žŒ์œผ๋กœ ์ธ์‹ํ•ด."

"key ๋Š” ํ˜ธํ…” ๋ฐฉ ๋ฒˆํ˜ธํŒ ๊ฐ™์€ ๊ฑฐ์•ผ. ์†๋‹˜์€ ๊ฐ™์•„๋„ ๋ฐฉ ๋ฒˆํ˜ธํŒ์„ ๋ฐ”๊พธ๋ฉด ์ฒดํฌ์ธ ๊ธฐ๋ก(์ƒํƒœ)์ด ์ดˆ๊ธฐํ™”๋ผ์„œ ์™„์ „ํžˆ ์ƒˆ ํˆฌ์ˆ™๊ฐ์œผ๋กœ ์ฒ˜๋ฆฌํ•ด."

"key ๋Š” ๊ฒŒ์ž„์˜ ์บ๋ฆญํ„ฐ ID ์•ผ. ์บ๋ฆญํ„ฐ ์ข…๋ฅ˜(ํƒ€์ž…)๊ฐ€ ๊ฐ™์•„๋„ ID ๊ฐ€ ๋‹ค๋ฅด๋ฉด ์•„์ดํ…œ(์ƒํƒœ)์ด ์—†๋Š” ์ƒˆ ์บ๋ฆญํ„ฐ๋กœ ์‹œ์ž‘ํ•ด."

๐Ÿ’ก ์ด ๋น„์œ ๋ฅผ ์ง์ ‘ ๋งŒ๋“ค์–ด๋ดค๋‹ค๋ฉด: ๊ฐœ๋…์„ ์™„๋ฒฝํžˆ ์ดํ•ดํ•œ ๊ฑฐ์˜ˆ์š”.


Q5. ์‹ฌํ™” ์ถ”๋ก  ๐Ÿ”ด

Q5. ์•„๋ž˜ ๋‘ ์ฝ”๋“œ์˜ ๋™์ž‘์ด ์–ด๋–ป๊ฒŒ ๋‹ค๋ฅธ์ง€ ์„ค๋ช…ํ•ด๋ณด์„ธ์š”.

// ์ฝ”๋“œ A
function App() {
  const [count, setCount] = useState(0);
  return (
    <div>
      {count % 2 === 0 ? <Counter /> : <Counter />}
      <button onClick={() => setCount(c => c + 1)}>์ฆ๊ฐ€</button>
    </div>
  );
}
 
// ์ฝ”๋“œ B
function App() {
  const [count, setCount] = useState(0);
  return (
    <div>
      {count % 2 === 0
        ? <Counter key="even" />
        : <Counter key="odd" />
      }
      <button onClick={() => setCount(c => c + 1)}>์ฆ๊ฐ€</button>
    </div>
  );
}
  • A) ์ฝ”๋“œ A, B ๋ชจ๋‘ ๋ฒ„ํŠผ์„ ๋ˆ„๋ฅผ ๋•Œ๋งˆ๋‹ค Counter ์ƒํƒœ๊ฐ€ ๋ฆฌ์…‹๋œ๋‹ค.
  • B) ์ฝ”๋“œ A ๋Š” Counter ์ƒํƒœ๊ฐ€ ์œ ์ง€๋˜๊ณ , ์ฝ”๋“œ B ๋Š” ๋ฒ„ํŠผ์„ ๋ˆ„๋ฅผ ๋•Œ๋งˆ๋‹ค Counter ์ƒํƒœ๊ฐ€ ๋ฆฌ์…‹๋œ๋‹ค.
  • C) ์ฝ”๋“œ A, B ๋ชจ๋‘ Counter ์ƒํƒœ๊ฐ€ ์œ ์ง€๋œ๋‹ค. key ๋Š” ์˜ํ–ฅ์„ ์ฃผ์ง€ ์•Š๋Š”๋‹ค.
  • D) ์ฝ”๋“œ A ์—์„œ Counter ์ƒํƒœ๋Š” ์œ ์ง€๋˜์ง€๋งŒ, ์ฝ”๋“œ B ์—์„œ๋Š” key ๊ฐ€ ์ง์ˆ˜/ํ™€์ˆ˜๋งˆ๋‹ค ๋‹ฌ๋ผ์ง€๋ฏ€๋กœ ๋งค๋ฒˆ ์ƒˆ ์ธ์Šคํ„ด์Šค๊ฐ€ ๋งˆ์šดํŠธ๋œ๋‹ค.

โœ… ์ •๋‹ต: B โ€” ๋‘ ์ฝ”๋“œ์˜ ์ฐจ์ด๊ฐ€ ๋ฐ”๋กœ key ์˜ ํ•ต์‹ฌ์ด์—์š”.

์ฝ”๋“œ A ๋ถ„์„:

  • ๊ฐ™์€ ์œ„์น˜์— ํ•ญ์ƒ Counter ํƒ€์ž… (์ง์ˆ˜๋“  ํ™€์ˆ˜๋“  ๊ฐ™์€ ํƒ€์ž…)
  • key ์—†์Œ โ†’ React ๋Š” ๋™์ผ ์ธ์Šคํ„ด์Šค๋กœ ์ธ์‹
  • ๋ฒ„ํŠผ์„ ๋ˆŒ๋Ÿฌ๋„ Counter ์ƒํƒœ ์œ ์ง€

์ฝ”๋“œ B ๋ถ„์„:

  • count ๊ฐ€ ์ง์ˆ˜์ผ ๋•Œ: key="even" Counter
  • count ๊ฐ€ ํ™€์ˆ˜์ผ ๋•Œ: key="odd" Counter
  • key ๊ฐ€ "even" โ†” "odd" ๋กœ ๋ฒˆ๊ฐˆ์•„ ๋ฐ”๋€œ โ†’ ๋งค ํด๋ฆญ๋งˆ๋‹ค ๊ธฐ์กด Counter ์–ธ๋งˆ์šดํŠธ + ์ƒˆ Counter ๋งˆ์šดํŠธ
  • ๋ฒ„ํŠผ์„ ๋ˆ„๋ฅผ ๋•Œ๋งˆ๋‹ค Counter ์ƒํƒœ๊ฐ€ 0์œผ๋กœ ๋ฆฌ์…‹๋จ

์˜ค๋‹ต ํ•ด์„ค:

  • A โ€” ์ฝ”๋“œ A ๋Š” ๋ฆฌ์…‹๋˜์ง€ ์•Š์•„์š”. key ์—†์ด ๊ฐ™์€ ์œ„์น˜, ๊ฐ™์€ ํƒ€์ž…์ด๋ฉด ์ƒํƒœ ์œ ์ง€์˜ˆ์š”.
  • C โ€” ์ฝ”๋“œ B ์—์„œ key ๋Š” ๊ฐ•๋ ฅํ•˜๊ฒŒ ์˜ํ–ฅ์„ ์ค˜์š”. key ๋ณ€๊ฒฝ = ์ƒˆ ์ธ์Šคํ„ด์Šค ๊ฐ•์ œ ๋งˆ์šดํŠธ์˜ˆ์š”.
  • D โ€” B ์˜ ์„ค๋ช…์€ ๋งž์ง€๋งŒ A ์˜ ์„ค๋ช…์ด ํ‹€๋ ธ์–ด์š”. ์ฝ”๋“œ A ์—์„œ๋Š” ์ƒํƒœ๊ฐ€ ์œ ์ง€๋ผ์š”.

๐Ÿ“Œ ํ•ต์‹ฌ ๊ธฐ์–ต๋ฒ•: key ๊ฐ€ ์—†์œผ๋ฉด ์œ„์น˜์™€ ํƒ€์ž…๋งŒ ๋ณด๊ณ  ํŒ๋‹จํ•ด์š”. key ๊ฐ€ ์žˆ์œผ๋ฉด key ๊นŒ์ง€ ์„ธ ๊ฐ€์ง€๋ฅผ ๋ชจ๋‘ ๋ด์š”. "๊ฐ™์€ ์œ„์น˜ + ๊ฐ™์€ ํƒ€์ž… + ๊ฐ™์€ key" ๊ฐ€ ๋˜์–ด์•ผ ๋™์ผ ์ธ์Šคํ„ด์Šค์˜ˆ์š”.


๐Ÿ”— ๋” ์•Œ์•„๋ณด๊ธฐ

์ด ๋ฌธ์„œ์—์„œ ๋‹ค๋ฃฌ ๋‚ด์šฉ๊ณผ ์—ฐ๊ฒฐ๋œ ๊ณต์‹ ๋ฌธ์„œ ๋ฐ ์‹ฌํ™” ํ•™์Šต ์ž๋ฃŒ์˜ˆ์š”:

  • React ๊ณต์‹ ๋ฌธ์„œ โ€” Preserving and Resetting State: React ๋ Œ๋” ํŠธ๋ฆฌ์™€ ์ƒํƒœ ๋ณด์กด/๋ฆฌ์…‹์— ๋Œ€ํ•œ ๊ณต์‹ ์„ค๋ช…์ด์—์š”. ์ด ๋ฌธ์„œ์˜ ํ•ต์‹ฌ ์›๋ฆฌ๊ฐ€ ์—ฌ๊ธฐ์„œ ๋‚˜์™”์–ด์š”.
  • React ๊ณต์‹ ๋ฌธ์„œ โ€” Rendering Lists: key ์˜ ๊ณต์‹ ์„ค๋ช…๊ณผ ์•ˆ์ •์ ์ธ key ๊ฐ’ ์„ ํƒ ๊ธฐ์ค€์„ ๋‹ค๋ค„์š”.
  • Dan Abramov ์˜ "Why Do React Elements Have a $$typeof Property?": React ๊ฐ€ ์ปดํฌ๋„ŒํŠธ ํƒ€์ž…์„ ์–ด๋–ป๊ฒŒ ๋น„๊ตํ•˜๋Š”์ง€ ๋‚ด๋ถ€ ๊ตฌํ˜„์„ ๊นŠ๊ฒŒ ๋‹ค๋ค„์š”.
  • Kent C. Dodds ์˜ "Understanding React's key prop": key ์˜ ๋™์ž‘ ์›๋ฆฌ๋ฅผ ์‹ค์šฉ์ ์ธ ์˜ˆ์ œ๋กœ ์„ค๋ช…ํ•ด์š”. ์ด ๋ฌธ์„œ์˜ ํŒจํ„ด๋“ค์— ํฐ ์˜๊ฐ์„ ์คฌ์–ด์š”.

๋‹ค์Œ์— ์ฝ์œผ๋ฉด ์ข‹์€ ๋ฌธ์„œ:

์ด ๋ฌธ์„œ์—์„œ ๋ฐฐ์šด ๋ Œ๋” ํŠธ๋ฆฌ์™€ ์ƒํƒœ ์œ„์น˜ ๊ฐœ๋…์€ React ์ตœ์ ํ™”์˜ ๊ธฐ๋ฐ˜์ด ๋ผ์š”. ๋‹ค์Œ ์ฃผ์ œ๋“ค๊ณผ ์ž์—ฐ์Šค๋Ÿฝ๊ฒŒ ์—ฐ๊ฒฐ๋ผ์š”:

  • React.memo ์™€ useMemo: ๋ Œ๋” ํŠธ๋ฆฌ์˜ ์–ด๋А ์œ„์น˜์—์„œ ๋ฆฌ๋ Œ๋”๋ง์„ ์ฐจ๋‹จํ• ์ง€ ๊ฒฐ์ •ํ•˜๋Š” ๋„๊ตฌ์˜ˆ์š”.
  • useReducer: ๋ณต์žกํ•œ ์ƒํƒœ ๋กœ์ง์„ ์ปดํฌ๋„ŒํŠธ ์™ธ๋ถ€๋กœ ๋ถ„๋ฆฌํ•˜๋Š” ๋ฐฉ๋ฒ•์ด์—์š”. ์ƒํƒœ๊ฐ€ ๋ Œ๋” ํŠธ๋ฆฌ ์œ„์น˜์— ์—ฐ๊ฒฐ๋œ๋‹ค๋Š” ์›๋ฆฌ๋Š” ๋™์ผํ•ด์š”.
  • Context ์™€ ์ƒํƒœ ๋Œ์–ด์˜ฌ๋ฆฌ๊ธฐ(State Lifting): ์—ฌ๋Ÿฌ ์ปดํฌ๋„ŒํŠธ๊ฐ€ ๊ฐ™์€ ์ƒํƒœ๋ฅผ ๊ณต์œ ํ•ด์•ผ ํ•  ๋•Œ ์ƒํƒœ๋ฅผ ์–ด๋А ํŠธ๋ฆฌ ์œ„์น˜์— ์˜ฌ๋ ค์•ผ ํ•˜๋Š”์ง€ ํŒ๋‹จํ•˜๋Š” ๊ธฐ์ค€์ด ๋ผ์š”.