๐Ÿงฉ 02. ์ƒํƒœ(State)์˜ ์ง„์งœ ์˜๋ฏธ โ€” ๋ Œ๋”๋ง์€ ์Šค๋ƒ…์ƒท์ด๋‹ค

๐Ÿ“‹ ๊ฐœ์š”

์ƒํƒœ(State)๊ฐ€ ์ผ๋ฐ˜ ๋ณ€์ˆ˜์™€ ์–ด๋–ป๊ฒŒ ๋‹ค๋ฅธ์ง€, ์™œ ๋น„๋™๊ธฐ ์•ˆ์—์„œ ์˜›๋‚  ๊ฐ’์„ ๋ณด๊ฒŒ ๋˜๋Š”์ง€(ํด๋กœ์ € ํ•จ์ •) ํŒŒํ—ค์นฉ๋‹ˆ๋‹ค.

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

  • setState๋ฅผ ํ˜ธ์ถœํ•ด๋„ ๋ฐ”๋กœ ๋‹ค์Œ ์ค„์—์„œ ๊ฐ’์ด ๋ฐ”๋€Œ์ง€ ์•Š๋Š” ์ด์œ ๋ฅผ ์„ค๋ช…ํ•  ์ˆ˜ ์žˆ๋‹ค.
  • ํƒ€์ด๋จธ๋‚˜ ๋น„๋™๊ธฐ ํ•จ์ˆ˜์—์„œ ์˜›๋‚  ์ƒํƒœ๊ฐ’(ํด๋กœ์ € ํ•จ์ •)์„ ์ฐธ์กฐํ•˜๋Š” ๋ฒ„๊ทธ๋ฅผ ์ฆ‰์‹œ ํŒŒ์•…ํ•  ์ˆ˜ ์žˆ๋‹ค.
  • ํ•จ์ˆ˜ํ˜• ์—…๋ฐ์ดํŠธ(setState(prev => prev + 1))๊ฐ€ ์–ธ์ œ ์™œ ํ•„์š”ํ•œ์ง€ ํŒ๋‹จํ•  ์ˆ˜ ์žˆ๋‹ค.

๐Ÿ“‹ ๋ชฉ์ฐจ


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

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

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

  • ์˜์ฒ (์‹ ์ž…): "์–ด๋ผ? '๊ฐ€์ž… ํ™˜์˜ ๋ฉ”์‹œ์ง€ ๋ณด๋‚ด๊ธฐ' ๋ฒ„ํŠผ์„ ๋ˆŒ๋ €๋Š”๋ฐ, 5์ดˆ ๋’ค์— ๋œจ๋Š” ํŒ์—…์— ๋ฐฉ๊ธˆ ์ž…๋ ฅํ•œ ์ˆ˜์‹ ์ž ์ด๋ฆ„์ด ์•ˆ ๋œจ๊ณ  ๋นˆ์นธ๋งŒ ๋‚˜์™€์š”! ์ œ๊ฐ€ ๊ท€์‹ ์„ ๋ณธ ๊ฑธ๊นŒ์š”?"
  • ์˜ํ˜ธ(๋ฆฌ๋“œ): "์˜์ฒ  ๋‹˜... ๋ฆฌ์•กํŠธ ๋ Œ๋”๋ง์€ ๋™์˜์ƒ์ด ์•„๋‹ˆ๋ผ '์‚ฌ์ง„(์Šค๋ƒ…์ƒท)' ์ด์—์š”. 5์ดˆ ์ „์— ์ฐ์–ด๋‘” ์‚ฌ์ง„ ์†์—๋Š” ๋‹น์—ฐํžˆ ๋นˆ์นธ ์ž…๋ ฅ์ฐฝ์ด ์ฐํ˜€ ์žˆ์—ˆ๊ฒ ์ฃ !"

๐Ÿค” ์™œ ์•Œ์•„์•ผ ํ•˜๋Š”๊ฐ€: ๋ณ€์ˆ˜๊ฐ€ ์•„๋‹Œ ์Šค๋ƒ…์ƒท

ํ”„๋ก ํŠธ์—”๋“œ ๊ฐœ๋ฐœ์ž๋“ค์ด ์ฒ˜์Œ ๋ฆฌ์•กํŠธ๋ฅผ ๋งŒ๋‚ฌ์„ ๋•Œ ๊ฐ€์žฅ ๋‹นํ™ฉํ•˜๋Š” ์ˆœ๊ฐ„์€ ์–ธ์ œ์ผ๊นŒ? ๋ถ„๋ช…ํžˆ ํ•จ์ˆ˜๋ฅผ ํ†ตํ•ด ๊ฐ’์„ ๋ฐ”๊ฟจ๋Š”๋ฐ, ์ฝ”๋“œ ๋ฐ”๋กœ ์•„๋žซ์ค„์—์„œ ์ฝ˜์†” ๋กœ๊ทธ๋กœ ๊ทธ ๊ฐ’์„ ์ฐ์–ด๋ณด๋ฉด ๋ฐ”๋€Œ๊ธฐ ์ „์˜ ๊ฐ’ ์ด ์—ฌ์ „ํžˆ ๋‚˜์˜ฌ ๋•Œ์•ผ.

๐Ÿค” ์ž ๊น, ๋จผ์ € ์ƒ๊ฐํ•ด๋ด
์•„๋ž˜ ์ฝ”๋“œ์—์„œ ๋ฒ„ํŠผ์„ ํด๋ฆญํ•˜๋ฉด ์ฝ˜์†” ์ฐฝ์— ์–ด๋–ค ์ˆซ์ž๊ฐ€ ์ฐํž๊นŒ?
setCount(count + 1); console.log(count);

// โŒ ์ˆœ์ง„ํ•œ ์ฝ”๋“œ (Naive Approach)
function Counter() {
  const [count, setCount] = useState(0);
 
  const handleClick = () => {
    setCount(count + 1);
    console.log(count); // 0์ผ๊นŒ, 1์ผ๊นŒ?
  };
  
  // ...

์œ„ ์ฝ”๋“œ์—์„œ count๋Š” 1์ด ๋˜์ง€ ์•Š๊ณ  ์—ฌ์ „ํžˆ 0์„ ์ถœ๋ ฅํ•ด. ์™œ ๊ทธ๋Ÿด๊นŒ?

React์—์„œ useState๋กœ ๋งŒ๋“  ์ƒํƒœ๋Š” ์ผ๋ฐ˜ ๋ณ€์ˆ˜๊ฐ€ ์•„๋‹ˆ๊ธฐ ๋•Œ๋ฌธ ์ด์•ผ. ์˜์ฒ ์ด๋Š” ์ด๊ฑธ ์ž๋ฐ”์Šคํฌ๋ฆฝํŠธ์˜ let count = 0์ฒ˜๋Ÿผ ์—ฌ๊ธฐ๊ณ  ๊ฐ’์ด ์ฆ‰์‹œ ํ• ๋‹น๋˜๋Š” ์ค„ ์•Œ์•˜์ง€๋งŒ, ๋ฆฌ์•กํŠธ๋Š” ์ด ๊ฐ’์„ **์Šค๋ƒ…์ƒท(Snapshot, ์‚ฌ์ง„)**์ฒ˜๋Ÿผ ์ทจ๊ธ‰ํ•ด.


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

๐Ÿง’ 5์‚ด์—๊ฒŒ ์„ค๋ช…ํ•œ๋‹ค๋ฉด?
๋„ค๊ฐ€ ๋ฐฉ์— ๋“ค์–ด๊ฐ€์„œ ๋ฐฉ๊ธˆ ํด๋ผ๋กœ์ด๋“œ ์‚ฌ์ง„์„ ํ•œ ์žฅ ์ฐฐ์นต ์ฐ์—ˆ์–ด. ๊ทธ ์‚ฌ์ง„ ์•ˆ์˜ ์‹œ๊ณ„๋Š” '12์‹œ ์ •๊ฐ'์„ ๊ฐ€๋ฆฌํ‚ค๊ณ  ์žˆ์ง€.
๋„ˆ๋Š” ์—„๋งˆํ•œํ…Œ "์—„๋งˆ, ์ €๊ธฐ ๋ฒฝ์‹œ๊ณ„ 12์‹œ 5๋ถ„์œผ๋กœ ๋Œ๋ ค์ค˜!" ํ•˜๊ณ  ์†Œ๋ฆฌ์ณค์–ด. (์ด๊ฒŒ setState ์•ผ).
์—„๋งˆ๊ฐ€ ๋ฒฝ์‹œ๊ณ„๋ฅผ 5๋ถ„ ๋Œ๋ ค๋†จ์ง€๋งŒ, ๋„ค ์†์— ๊ฝ‰ ์ฅ๊ณ  ์žˆ๋Š” ํด๋ผ๋กœ์ด๋“œ ์‚ฌ์ง„ ์† ์‹œ๊ณ„ ๋Š” ์—ฌ์ „ํžˆ 12์‹œ ์ •๊ฐ์ด์•ผ. ์‚ฌ์ง„์€ ์‹ค์‹œ๊ฐ„ ๋น„๋””์˜ค๊ฐ€ ์•„๋‹ˆ๋‹ˆ๊นŒ!
๋‹ค์Œ ๋ฒˆ์— ์—„๋งˆ๊ฐ€ "์‹œ๊ณ„ ๋ฐ”๊ฟจ์œผ๋‹ˆ ์‚ฌ์ง„ ๋‹ค์‹œ ์ฐ์–ด๋ด!" ํ•˜๊ณ  ์ƒˆ๋กœ ์ฐฐ์นต ์ฐ์„ ๋•Œ(๋‹ค์Œ ๋ฆฌ๋ Œ๋”๋ง), ๊ทธ์ œ์„œ์•ผ 12์‹œ 5๋ถ„์ด ์ฐํžŒ ์ƒˆ๋กœ์šด ํด๋ผ๋กœ์ด๋“œ ์‚ฌ์ง„ ์„ ๋ฐ›๊ฒŒ ๋˜๋Š” ๊ฑฐ์•ผ.

โœ… ํ•ต์‹ฌ ์›๋ฆฌ:
๋ Œ๋”๋ง์ด๋ž€, ๋ฆฌ์•กํŠธ๊ฐ€ ์ปดํฌ๋„ŒํŠธ(ํ•จ์ˆ˜)๋ฅผ ํ˜ธ์ถœ ํ•˜๋Š” ํ–‰์œ„์•ผ. ๊ทธ ํ•จ์ˆ˜๊ฐ€ ํ˜ธ์ถœ๋œ ๋”ฑ ๊ทธ ์ˆœ๊ฐ„์˜ state ๊ฐ’๊ณผ props ๊ฐ’์„ ๊ฐ€์ง€๊ณ  UI(JSX)๋ฅผ ๋งŒ๋“ค์–ด๋‚ด์ง€. ๊ทธ ๋ Œ๋”๋ง ์•ˆ์—์„œ ์‚ด์•„๊ฐ€๋Š” ์ด๋ฒคํŠธ ํ•ธ๋“ค๋Ÿฌ(handleClick) ์—ญ์‹œ ํ•จ์ˆ˜๊ฐ€ ๋งŒ๋“ค์–ด์ง€๋˜ ๊ทธ ์ˆœ๊ฐ„์˜ ๊ณ ์ •๋œ ์Šค๋ƒ…์ƒท(์˜ˆ: count = 0) ์— ๊ฐ‡ํžˆ๊ฒŒ ๋ผ. ์ด๋ฅผ ์ „๋ฌธ ์šฉ์–ด๋กœ ์ž๋ฐ”์Šคํฌ๋ฆฝํŠธ์˜ ํด๋กœ์ €(Closure) ๋ผ๊ณ  ํ•ด.


๐Ÿงฉ ํด๋กœ์ €(Closure)๊ฐ€ ๋ถ€๋ฅธ ๋Œ€์ฐธ์‚ฌ

โŒ ์˜์ฒ ์ด์˜ ํญํƒ„ ์ฝ”๋“œ: ์ข‹์•„์š” 3๋ฐฐ ์ด๋ฒคํŠธ

์ปค๋ฎค๋‹ˆํ‹ฐ ๊ธ€์— '3๋ฐฐ ์ข‹์•„์š” ์ด๋ฒคํŠธ' ๋ฒ„ํŠผ์„ ๊ธด๊ธ‰ ์ถ”๊ฐ€ํ•˜๊ฒŒ ๋˜์—ˆ์–ด. ๋ˆ„๋ฅด๋ฉด ์ข‹์•„์š”๊ฐ€ ํ•œ ๋ฒˆ์— 3์”ฉ ์˜ฌ๋ผ๊ฐ€์•ผ ํ•ด.

// โŒ ์ˆœ์ง„ํ•œ ์ฝ”๋“œ: ๋„๋Œ€์ฒด ์™œ 3์”ฉ ์•ˆ ์˜ค๋ฅผ๊นŒ?
function LikeButton() {
  const [likes, setLikes] = useState(0);
 
  const handleTripleLike = () => {
    setLikes(likes + 1);
    setLikes(likes + 1);
    setLikes(likes + 1);
  };
 
  return <button onClick={handleTripleLike}>์ข‹์•„์š” {likes}</button>;
}

์˜์ฒ ์ด๋Š” ํ˜ธ๊ธฐ๋กญ๊ฒŒ ๋ฒ„ํŠผ์„ ๋ˆŒ๋ €์ง€๋งŒ, ๊ฒฐ๊ณผ๋Š” ์ถฉ๊ฒฉ์ ์ด๊ฒŒ๋„ likes๊ฐ€ 1 ๋งŒ ์˜ฌ๋ž์–ด. ์™œ๋ƒ๊ณ ?

  1. ์ฒซ ๋ฒˆ์งธ ๋ Œ๋”๋ง ์Šค๋ƒ…์ƒท์—์„œ likes๋ผ๋Š” ์ƒ์ˆ˜์˜ ๊ฐ’์€ 0์ด์•ผ.
  2. setLikes(0 + 1)์„ ์‹คํ–‰. ๋ฆฌ์•กํŠธ์— "๋‹ค์Œ ๋ Œ๋”๋ง ๋• 1๋กœ ์ค˜" ์˜ˆ์•ฝ.
  3. setLikes(0 + 1)์„ ์‹คํ–‰. ์—ฌ์ „ํžˆ ๋‚ด ํ•ธ๋“ค๋Ÿฌ๊ฐ€ ๋“ค๊ณ  ์žˆ๋Š” ์‚ฌ์ง„ ์† likes๋Š” 0์ด๋‹ˆ๊นŒ!
  4. setLikes(0 + 1)์„ ์‹คํ–‰. ์—ญ์‹œ๋‚˜ 0 + 1.

๊ฒฐ๊ตญ ๋ฆฌ์•กํŠธ๋Š” ๋ Œ๋”๋ง์ด ๋๋‚  ๋•Œ ์ผ๊ด„ ์ฒ˜๋ฆฌ(Batching)๋ฅผ ํ•˜๋ฉด์„œ "์•„, 1๋กœ ๋ฐ”๊ฟ”๋‹ฌ๋ผ๋Š” ์š”์ฒญ์ด 3๋ฒˆ ์—ฐ์†์œผ๋กœ ์™”๊ตฌ๋‚˜. ์•Œ์•˜์–ด, 1๋กœ ๋ฎ์–ด์”Œ์šธ๊ฒŒ." ํ•˜๊ณ  ์ตœ์ข…์ ์œผ๋กœ 1๋กœ ์—…๋ฐ์ดํŠธํ•ด๋ฒ„๋ฆฌ์ง€.

โœ… ์˜ํ˜ธ์˜ ๋ฆฌํŒฉํ† ๋ง: ํ•จ์ˆ˜ํ˜• ์—…๋ฐ์ดํŠธ (Functional Update)

์ด๋Ÿด ๋•Œ ์Šค๋ƒ…์ƒท(ํด๋กœ์ €)์˜ ๋ฒฝ์„ ๋šซ๊ณ  ๊ฐ€์žฅ ์ตœ์‹  ํ˜•ํƒœ์˜ ๋ณด์žฅ๋œ ์ƒํƒœ ๋ฅผ ์–ป์–ด์˜ค๊ณ  ์‹ถ๋‹ค๋ฉด ์–ด๋–ป๊ฒŒ ํ•ด์•ผ ํ• ๊นŒ? ๋ฐ”๋กœ setState ์•ˆ์— ๊ฐ’์„ ๋˜์ง€๋Š” ๋Œ€์‹  ๊ทœ์น™(ํ•จ์ˆ˜) ์„ ์ง‘์–ด๋„ฃ๋Š” ๊ฑฐ์•ผ.

// โœ… ์šฐ์•„ํ•œ ์ฝ”๋“œ (Pro Approach)
function LikeButton() {
  const [likes, setLikes] = useState(0);
 
  const handleTripleLike = () => {
    // ๊ฐ’์„ ์ง์ ‘ ๊ณ„์‚ฐํ•ด ๋„ฃ์ง€ ๋ง๊ณ , "์ด์ „ ๊ฐ’์„ ๋ฐ›์•„์„œ ์–ด๋–ป๊ฒŒ ๋ณ€ํ™˜ํ• ์ง€" ๊ทœ์น™์„ ์ „๋‹ฌํ•ด!
    setLikes(prevLikes => prevLikes + 1);
    setLikes(prevLikes => prevLikes + 1);
    setLikes(prevLikes => prevLikes + 1);
  };
 
  return <button onClick={handleTripleLike}>์ข‹์•„์š” {likes}</button>;
}

๐Ÿ“– ์šฉ์–ด: ํ•จ์ˆ˜ํ˜• ์—…๋ฐ์ดํŠธ (Functional Update)
์ƒํƒœ ์—…๋ฐ์ดํŠธ ํ•จ์ˆ˜์— ๊ฐ’ ๋Œ€์‹  (์ด์ „_์ƒํƒœ) => ๋‹ค์Œ_์ƒํƒœ ํ˜•ํƒœ์˜ ์ฝœ๋ฐฑ ํ•จ์ˆ˜๋ฅผ ์ „๋‹ฌํ•˜๋Š” ๋ฐฉ์‹.
์ด ํ•จ์ˆ˜๋“ค์€ ๋ฆฌ์•กํŠธ ๋‚ด๋ถ€์˜ ํ(Queue)์— ๋‹ด๊ฒจ์„œ ์ฐจ๋ก€๋Œ€๋กœ ์‹คํ–‰๋˜๋ฏ€๋กœ, ๋‚ด ์Šค์ฝ”ํ”„์˜ ์˜ค๋ž˜๋œ ์Šค๋ƒ…์ƒท ๊ฐ’์„ ๋ฌด์‹œํ•˜๊ณ  ํ•ญ์ƒ ์ตœ์‹ ์˜ ์ƒํƒœ ๊ฒฐ๊ด๊ฐ’(prevLikes) ์„ ๋ฌผ๊ณ  ์ด์–ด์งˆ ์ˆ˜ ์žˆ๋‹ค.


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

โŒ ๋น„๋™๊ธฐ(setTimeout) ํƒ€์ด๋จธ์˜ ์นจ๋ฌต ๋ฒ„๊ทธ

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

const [message, setMessage] = useState('');
 
const handleSend = () => {
  setTimeout(() => {
    alert(`์„œ๋ฒ„์— ์ „์†ก๋œ ๋‚ด์šฉ: ${message}`); // ๐Ÿ’ฅ 5์ดˆ ๋’ค์— ํ…… ๋นˆ ๋ฉ”์‹œ์ง€๊ฐ€ ๋œธ!
  }, 5000);
};
 
// ... <input onChange={(e) => setMessage(e.target.value)} /> ...

์›์ธ: handleSend ๊ฐ€ ์‹คํ–‰๋˜๋˜ ํƒ€์ด๋ฐ์˜ ๋ Œ๋”๋ง ์Šค๋ƒ…์ƒท์—์„œ message ๋Š” ํ…… ๋นˆ ๋ฌธ์ž์—ด์ด์—ˆ์–ด! ๋„ค๊ฐ€ ๊ทธ 5์ดˆ ์‚ฌ์ด์— ์ธํ’‹์ฐฝ์— ๋ฏธ์นœ ๋“ฏ์ด ํ‚ค๋ณด๋“œ๋ฅผ ํƒ€์ดํ•‘ํ•ด์„œ ์ปดํฌ๋„ŒํŠธ ์‚ฌ์ง„์ด 10์žฅ์ด๋‚˜ ์ƒˆ๋กœ ์ฐํ˜”์–ด๋„, ํƒ€์ด๋จธ ์•ˆ์— ์ ์–ด๋‘” ์ฝ”๋“œ๋Š” ์ฒ˜์Œ ๋ฒ„ํŠผ์„ ๋ˆŒ๋ €๋˜ 5์ดˆ ์ „ ๋‚ก์€ ์‚ฌ์ง„ ์† ๋นˆ message ์— ์˜์›ํžˆ ๊ฐ‡ํ˜€์žˆ์–ด. ์ด๊ฒŒ ๋ฐ”๋กœ ์˜ˆ์ „ ์ƒํƒœ๋ฅผ ๊ผญ ์ฅ๊ณ  ๋†“์ง€ ์•Š๋Š” 'ํด๋กœ์ €(Closure) ํ•จ์ •' ์ด์•ผ.

ํ•ด๊ฒฐ์ฑ…:
์ด๋Ÿด ๋•Œ๋Š” ์ƒํƒœ(์Šค๋ƒ…์ƒท)๊ฐ€ ์•„๋‹ˆ๋ผ, ๋ Œ๋”๋ง ์Šค๋ƒ…์ƒท๊ณผ ๋ฌด๊ด€ํ•˜๊ฒŒ ์–ธ์ œ๋‚˜ ํ˜„์žฌ ๋ฉ”๋ชจ๋ฆฌ ์ฃผ์†Œ์—์„œ ์ตœ์‹ ๊ฐ’์„ ๊บผ๋‚ด๋ณผ ์ˆ˜ ์žˆ๋Š” ์ž๋ฐ”์Šคํฌ๋ฆฝํŠธ ๊ฐ์ฒด์˜ ๋น„๋ฐ€ ์ฐฝ๊ณ , useRef ๋ฅผ ์จ์•ผ ํ•ด.


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

์ƒํ™ฉโŒ ๋‚˜์œ ์˜ˆ (์Šค๋ƒ…์ƒท ํ•จ์ •)โœ… ์ข‹์€ ์˜ˆ (ํ•จ์ˆ˜ํ˜• ์—…๋ฐ์ดํŠธ / Ref)
์ƒํƒœ ์—ฐ์† ์—…๋ฐ์ดํŠธsetCount(count + 1); setCount(count + 1);setCount(c => c + 1); setCount(c => c + 1);
๋น„๋™๊ธฐ ํƒ€์ž„์•„์›ƒ ์•ˆ์—์„œ ์ตœ์‹ ๊ฐ’ ํ•„์š”setTimeout(() => console.log(state), 1000)์ƒํƒœ๊ฐ€ ๋ณ€๊ฒฝ๋  ๋•Œ๋งˆ๋‹ค ref.current = state๋กœ ๋™๊ธฐํ™” ํ›„, ref.current๋กœ ์ฝ๊ธฐ

๐Ÿ’ก ํ•œ ์ค„๋กœ ๊ธฐ์–ตํ•˜๊ธฐ
๋ฆฌ์•กํŠธ์˜ ์ƒํƒœ(State)๋Š” ๋ณ€์ˆ˜๊ฐ€ ์•„๋‹ˆ๋ผ ํด๋ผ๋กœ์ด๋“œ ์‚ฌ์ง„(์Šค๋ƒ…์ƒท) ์ด๋‹ค.
๋นˆ๋ฒˆํ•œ ์ƒํƒœ ์—…๋ฐ์ดํŠธ๋Š” ๋‚ด ์†์— ๋“ค๋ฆฐ ๊ทธ ๋‚ก์€ ์‚ฌ์ง„์— ๋นจ๊ฐ„ํŽœ์„ ์น ํ•˜๋Š” ๊ฒŒ ์•„๋‹ˆ๋‹ค. "๋‹ค์Œ ๋ฒˆ์— ์ด๋Ÿฐ ํฌ์ฆˆ๋กœ ์‚ฌ์ง„ ๋‹ค์‹œ ์ฐ์–ด์ฃผ์„ธ์š”"ํ•˜๊ณ  ๋ฆฌ์•กํŠธ ์ŠคํŠœ๋””์˜ค ์‚ฌ์žฅ๋‹˜๊ป˜ ์˜ˆ์•ฝ์„œ๋ฅผ ์ ‘์ˆ˜ํ•˜๋Š” ํ–‰์œ„๋‹ค.


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

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

๐Ÿ’ก "์ƒํƒœ๋Š” ์ผ๋ฐ˜ ๋ณ€์ˆ˜๊ฐ€ ์•„๋‹ˆ๋ผ ํด๋ผ๋กœ์ด๋“œ ์‚ฌ์ง„(์Šค๋ƒ…์ƒท)์ด๋‹ค. ์ตœ์‹  ๊ฐ’์„ ๋ณด์žฅ๋ฐ›๊ณ  ์‹ถ๋‹ค๋ฉด ํ•จ์ˆ˜ํ˜• ์—…๋ฐ์ดํŠธ๋ฅผ ์“ฐ์ž!"

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


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

Q1. ๋‹ค์Œ ์ปดํฌ๋„ŒํŠธ์—์„œ ๋ฒ„ํŠผ์„ ํ•œ ๋ฒˆ ํด๋ฆญํ•˜๋ฉด, ํ™”๋ฉด์—๋Š” ์ตœ์ข…์ ์œผ๋กœ ์–ด๋–ค ๊ฐ’์ด ๋ Œ๋”๋ง๋ ๊นŒ์š”?

function QuizOne() {
  const [score, setScore] = useState(0);
 
  const raiseScore = () => {
    setScore(score + 5);
    setScore(score + 5);
    setScore(s => s + 2);
  };
 
  return <button onClick={raiseScore}>์ ์ˆ˜: {score}</button>;
}
  • A) 12
  • B) 7
  • C) 5
  • D) 2

โœ… ์ •๋‹ต: B

๐Ÿ’ก ์ƒ์„ธ ํ•ด์„ค: ์ฒซ ์ค„ setScore(0 + 5)๋กœ ๊ฐ’ '5'๋กœ ๊ต์ฒด ์˜ˆ์•ฝ์ด ๋“ค์–ด๊ฐ‘๋‹ˆ๋‹ค. ๋‘ ๋ฒˆ์งธ ์ค„ setScore(0 + 5)์—ญ์‹œ ๋‚ด ์†์˜ ์Šค๋ƒ…์ƒท์€ 0์ด๋ฏ€๋กœ '5'๋กœ ๊ต์ฒด ์˜ˆ์•ฝ(๋™์ผ ๊ฐ’์œผ๋กœ ๋ฎ์–ด์”Œ์›€)์„ ํ•ฉ๋‹ˆ๋‹ค. ๋งˆ์ง€๋ง‰ ์ค„ setScore(s => s + 2)๋Š” ํ(Queue) ์—ฐ์‚ฐ์ด๋ฏ€๋กœ ํ์— ๊ฐ€์žฅ ๋งˆ์ง€๋ง‰์œผ๋กœ ์Œ“์ธ ์ตœ์‹  ๊ฒฐ๊ณผ๊ฐ’์ธ '5'๋ฅผ ๋ฌผ๋ ค๋ฐ›์•„ 5 + 2 = 7์„ ๋ฐ˜ํ™˜ํ•ฉ๋‹ˆ๋‹ค. ๋”ฐ๋ผ์„œ ๋‹ค์Œ ๋ฒˆ ์Šค๋ƒ…์ƒท์˜ ๋ Œ๋”๋ง ๊ฐ’์€ 7์ด ๋ฉ๋‹ˆ๋‹ค!

Q2. useRef๋Š” ์ƒํƒœ ๋ณ€์ˆ˜(useState)์™€ ๋‹ฌ๋ฆฌ ํด๋กœ์ €(์˜›๋‚  ์‚ฌ์ง„) ํ•จ์ •์— ๋น ์ง€์ง€ ์•Š์Šต๋‹ˆ๋‹ค. ๊ทธ ๊ทผ๋ณธ์ ์ธ ์ด์œ ๋Š” ๋ฌด์—‡์ผ๊นŒ์š”?

  • A) useRef๋Š” ๋ธŒ๋ผ์šฐ์ €์˜ ์ „์—ญ ๊ฐ์ฒด์ธ Window์— ๊ฐ’์„ ์ง์ ‘ ์ €์žฅํ•˜๊ธฐ ๋•Œ๋ฌธ.
  • B) useRef๋Š” ๋‚ด์šฉ๋ฌผ์ด ๋ฐ”๋€Œ๋ฉด ํ™”๋ฉด์„ ๊ฐ•์ œ๋กœ ์ฆ‰์‹œ ๋ฆฌ๋ Œ๋”๋ง์‹œํ‚ค๊ธฐ ๋•Œ๋ฌธ.
  • C) ์ปดํฌ๋„ŒํŠธ์˜ ๋ Œ๋”๋ง ์ƒ๋ช…์ฃผ๊ธฐ์™€ ๋ฌด๊ด€ํ•˜๊ฒŒ, ํž™(Heap) ๋ฉ”๋ชจ๋ฆฌ ๊ณต๊ฐ„์— ํ•˜๋‚˜์˜ ๋™์ผํ•œ ์ฃผ์†Œ(reference)๋ฅผ ๊ฐ€์ง„ ๊ฐ์ฒด๋ฅผ ์˜๊ตฌ ์ง€์†์‹œํ‚ค๊ธฐ ๋•Œ๋ฌธ.
  • D) useRef๋Š” ๋น„๋™๊ธฐ ํ•จ์ˆ˜ ์•ˆ์—์„œ๋งŒ ๋™์ž‘ํ•˜๋„๋ก ํŠน์ˆ˜ ์„ค๊ณ„๋œ API์ด๊ธฐ ๋•Œ๋ฌธ.

โœ… ์ •๋‹ต: C

๐Ÿ’ก ์ƒ์„ธ ํ•ด์„ค: useState๋Š” ๋ Œ๋”๋ง๋งˆ๋‹ค ์ƒˆ๋กœ์šด ์ƒ์ˆ˜(const) ๊ฐ’์„ ๋˜์ ธ์ฃผ์ง€๋งŒ, useRef๋Š” ์–ธ์ œ๋‚˜ ๊ฐ™์€ ๋ฐ”๊ตฌ๋‹ˆ์ธ { current: ๊ฐ’ }์ด๋ผ๋Š” ์ž๋ฐ”์Šคํฌ๋ฆฝํŠธ ๊ฐ์ฒด์˜ '๋™์ผํ•œ ๋ฉ”๋ชจ๋ฆฌ ์ฃผ์†Œ'๋ฅผ ๋˜์ ธ์ค๋‹ˆ๋‹ค. ํ•จ์ˆ˜๊ฐ€ ํด๋กœ์ € ํƒ“์— ๊ณผ๊ฑฐ์˜ ๋ฐ”๊ตฌ๋‹ˆ ๊ป๋ฐ๊ธฐ๋ฅผ ์ฅ๊ณ  ์žˆ๋”๋ผ๋„, ๊ทธ ๋ฐ”๊ตฌ๋‹ˆ์˜ ์ฃผ์†Œ๊ฐ€ ์˜์›ํžˆ ๊ฐ™๊ธฐ ๋•Œ๋ฌธ์— ์–ธ์ œ๋“  ๋šœ๊ป‘(current)์„ ์—ด๋ฉด ๋ˆ„๊ตฐ๊ฐ€ ์ƒˆ๋กœ ์ง‘์–ด๋„ฃ์€ ๊ฐ€์žฅ ์Œฉ์Œฉํ•œ ์ตœ์‹  ๊ฐ’์„ ๋“ค์—ฌ๋‹ค๋ณผ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ๋ Œ๋”๋ง ํญํ’์—์„œ ์ž์œ ๋กœ์šด ๋‹จ ํ•˜๋‚˜์˜ '์Šค์œ„์Šค ์€ํ–‰ ๋น„๋ฐ€ ๊ธˆ๊ณ '์ธ ์…ˆ์ด์ฃ .

Q3. ๋ฆฌ์•กํŠธ๋Š” ์ƒํƒœ ์—…๋ฐ์ดํŠธ๋ฅผ ์™œ ๊ตณ์ด ์ด๋Ÿฐ '์˜ˆ์•ฝ ๋ฐ ๋ Œ๋”๋ง(Batching)' ๋ฐฉ์‹์œผ๋กœ ๊ท€์ฐฎ๊ฒŒ ์„ค๊ณ„ํ–ˆ์„๊นŒ์š”? ๋งŒ์•ฝ setState๋ฅผ ํ˜ธ์ถœํ•˜์ž๋งˆ์ž ๋ณ€์ˆ˜๊ฐ€ ๊ฐฑ์‹ ๋˜๊ณ  ์ฆ‰์‹œ ํ™”๋ฉด DOM์„ ์ง์ ‘ ๊ณ ์ณ๋ฒ„๋ฆฌ๋Š” ๋ฐฉ์‹์ด์—ˆ๋‹ค๋ฉด ์ƒ๊ธธ ์น˜๋ช…์  ๋‹จ์ ์€ ๋ฌด์—‡์ผ๊นŒ์š”?

โœ… ์ •๋‹ต ๋ฐ ์ฃผ๊ด€์‹ ํ•ด์„ค:

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