๐ŸŽจ 08. useRef: ๋ Œ๋”๋ง์„ ํ”ผํ•˜๋Š” ๋น„๋ฐ€ ๊ธˆ๊ณ 

๐Ÿ“‹ ๊ฐœ์š”

ํ•ญ์ƒ ์ตœ์‹  ๊ฐ’์„ ์œ ์ง€ํ•ด์•ผ ํ•˜์ง€๋งŒ ํ™”๋ฉด์ด ๋ฆฌ๋ Œ๋”๋ง๋˜๋Š” ๊ฒƒ์€ ์›์น˜ ์•Š์„ ๋•Œ, useRef๊ฐ€ ์–ด๋–ค ์—ญํ• ์„ ํ•˜๋Š”์ง€ ๋‚ด๋ถ€ ์›๋ฆฌ์™€ ํ•จ๊ป˜ ํŒŒํ—ค์นฉ๋‹ˆ๋‹ค.

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

  • useRef๊ฐ€ ๋‹จ์ˆœํžˆ <input> ์ฐฝ์— ํฌ์ปค์Šค๋ฅผ ๋งž์ถ”๋Š” DOM ์—ฐ๊ฒฐ ๋„๊ตฌ๊ฐ€ ์•„๋‹˜์„ ์•Œ๊ฒŒ ๋œ๋‹ค.
  • ์ƒํƒœ(useState)์™€ ์ฐธ์กฐ(useRef)์˜ ๋ณธ์งˆ์ ์ธ ๊ธฐ์ˆ ์  ์ฐจ์ด๋ฅผ ์Šค๋ƒ…์ƒท vs ์˜๊ตฌ ๋ณ€์ˆ˜ ๋ฉ˜ํƒˆ ๋ชจ๋ธ๋กœ ๊ตฌ๋ถ„ํ•  ์ˆ˜ ์žˆ๋‹ค.
  • ํ™”๋ฉด ์—…๋ฐ์ดํŠธ ์—†์ด ๋ถˆ๋ณ€ํ•˜๋Š” ๊ฐ’์„ ์€๋ฐ€ํžˆ ์ถ”์ ํ•˜๊ณ  ์‹ถ์„ ๋•Œ(ํƒ€์ด๋จธ ID ์ €์žฅ, ์ด์ „ ์ƒํƒœ ์ถ”์ ) useRef๋ฅผ ํ›Œ๋ฅญํ•˜๊ฒŒ ์„ค๊ณ„ํ•  ์ˆ˜ ์žˆ๋‹ค.

๐Ÿ“‹ ๋ชฉ์ฐจ


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

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

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

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

๐Ÿค” ์™œ ์•Œ์•„์•ผ ํ•˜๋Š”๊ฐ€: ์š”๋™์น˜๋Š” ์ปดํฌ๋„ŒํŠธ๋ฅผ ๊ฒฌ๋””๋Š” ๋‹ป

๋Œ€๋ถ€๋ถ„์˜ React ์˜ˆ์ œ ๋ฌธ์„œ๋ฅผ ๋ณด๋ฉด useRef๋ฅผ ์ฒ˜์Œ ์†Œ๊ฐœํ•  ๋•Œ ๊ผญ **"DOM ์กฐ์ž‘(<input ref={myRef}>)์„ ์œ„ํ•œ ๊ฐˆ๊ณ ๋ฆฌ์ž…๋‹ˆ๋‹ค~"**๋ผ๊ณ  ๊ฐ€๋ฅด์ณ. ํ•˜์ง€๋งŒ ์ด๊ฑด useRef ๋Šฅ๋ ฅ์น˜ ์ค‘ ๋น™์‚ฐ์˜ ์ผ๊ฐ๋„ ์•ˆ ๋˜๋Š” 10%์˜ ๋ถ€๊ฐ€ ๊ธฐ๋Šฅ์— ๋ถˆ๊ณผํ•ด.

๐Ÿค” ์ž ๊น, ๋จผ์ € ์ƒ๊ฐํ•ด๋ด
์Šคํ†ฑ์›Œ์น˜ ์ฝ”๋“œ๋ฅผ ์งœ๋ ค๊ณ  ํ•ด. ํƒ€์ด๋จธ๋ฅผ ๋ฉˆ์ถ”๋ ค๋ฉด ์ž๋ฐ”์Šคํฌ๋ฆฝํŠธ์˜ clearInterval(์•„์ด๋””๊ณ ์œ ๋ฒˆํ˜ธ)๊ฐ€ ํ•„์š”ํ•˜์ง€.
์ด ๊ณ ์œ  ๋ฒˆํ˜ธ๋ฅผ ๋ Œ๋”๋ง ์‚ฌ์ดํด์ด ๋Œ์•„๋„ ๊ธฐ์–ตํ•˜๋ ค๋ฉด ์–ด๋””๋‹ค ๋ณ€์ˆ˜๋ฅผ ๋งŒ๋“ค์–ด์•ผ ํ• ๊นŒ?

// โŒ ์˜์ฒ ์ด์˜ ํญํƒ„ ํˆฌ์ฒ™ (์ƒํƒœ ์˜ค๋‚จ์šฉ)
function Stopwatch() {
  const [seconds, setSeconds] = useState(0);
  const [timerId, setTimerId] = useState(null); // ๐Ÿšจ ํ™”๋ฉด์— ๊ทธ๋ฆฌ์ง€๋„ ์•Š์„ ๊ฑด๋ฐ ๊ตณ์ด ์ƒํƒœ๋กœ ๋งŒ๋“ฆ!
 
  const handleStart = () => {
    const id = setInterval(() => setSeconds(s => s + 1), 1000);
    setTimerId(id); // ๋ถˆํ•„์š”ํ•˜๊ฒŒ ์ƒํƒœ ๊ฐฑ์‹  ๋ฐœ๋™! -> ๋ฌด์˜๋ฏธํ•œ ๋ Œ๋”๋ง 1ํšŒ ์ถ”๊ฐ€ ๋ฐœ์‚ฌ!
  };
 
  const handleStop = () => {
    clearInterval(timerId);
  };
 
  return (
    <div>
      <p>๊ฒฝ๊ณผ ์‹œ๊ฐ„: {seconds}์ดˆ</p>
      <button onClick={handleStart}>์‹œ์ž‘</button>
      <button onClick={handleStop}>๋ฉˆ์ถฐ!</button>
    </div>
  );
}

์˜์ฒ ์ด ์ฝ”๋“œ๋Š” ์–ผํ• ๋ฌธ์ œ๊ฐ€ ์—†์–ด ๋ณด์—ฌ(๊ตฌ๋™์€ ๋˜๋‹ˆ๊นŒ).
ํ•˜์ง€๋งŒ ์ด๊ฑด ์•„์—ฐ์‹ค์ƒ‰ํ•  ํผํฌ๋จผ์Šค ์“ฐ๋ ˆ๊ธฐ ์ฝ”๋“œ์ž…๋‹ˆ๋‹ค. timerId๋Š” ํ™”๋ฉด UI์˜ ํ”ฝ์…€ ๋‹จ ํ•˜๋‚˜๋„ ๋ฐ”๊พธ์ง€ ์•Š๋Š”๋ฐ, ์–˜๋ฅผ ๊ฐฑ์‹ ํ•œ๋‹ต์‹œ๊ณ  setTimerId(id)๋ฅผ ๋•Œ๋ฆฌ๋Š” ์ˆœ๊ฐ„ ๋ฆฌ์•กํŠธ ์ „์ฒด ์—”์ง„์ด "์•—! ์ƒํƒœ ๋ณ€๊ฒฝ! ๋ Œ๋”๋ง ํŠธ๋ฆฌ ํƒ์ƒ‰!" ์š”๋™์„ ์น˜๋ฉฐ ํ™”๋ฉด ์ „์ฒด๋ฅผ ๋ถˆํ•„์š”ํ•˜๊ฒŒ ์ƒˆ๋กœ ๊ทธ๋ฆฝ๋‹ˆ๋‹ค.

์šฐ๋ฆฌ์—๊ฒ **"๊ฐ’์„ ์•ˆ์ „ํ•˜๊ฒŒ ์ €์žฅํ•˜๋˜, ๊ฐ’์ด ๋ฐ”๋€๋‹ค๊ณ  ์—„๋งˆ(React)ํ•œํ…Œ ์ผ๋Ÿฌ์ผ๋Ÿฌ ๋ Œ๋”๋ง ํญํ’์„ ๋ถ€๋ฅด์ง€๋Š” ์•Š๋Š” ๋น„๋ฐ€ ์ฐฝ๊ณ "**๊ฐ€ ์ ˆ๋Œ€์ ์œผ๋กœ ํ•„์š”ํ•ฉ๋‹ˆ๋‹ค. ๊ทธ๋ฆฌ๊ณ  ๊ทธ๊ฒŒ ๋ฐ”๋กœ useRef์˜ ๋ณธ์งˆ์ž…๋‹ˆ๋‹ค.


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

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

  1. useState๋Š” ๋ฐฉ์†ก๊ตญ ๋งˆ์ดํฌ์•ผ. ๋งˆ์ดํฌ์— ๋Œ€๊ณ  ์ˆซ์ž๋ฅผ ๋ฐ”๊พธ๋ฉด ์˜จ ๋™๋„ค ๋งˆ์„ ์‚ฌ๋žŒ๋“ค(์ปดํฌ๋„ŒํŠธ๋“ค)์ด ๋‹ค ๋ฆฌ์…‹๋ผ์„œ ๋‹ค์‹œ ๋“ค์œผ๋Ÿฌ ๊ด‘์žฅ์œผ๋กœ ๋ชจ์ด์ง€(๋ฆฌ๋ Œ๋”๋ง ํŒŒํ‹ฐ).

  2. useRef๋Š” ๋„ค ๋ฐ”์ง“๋‹จ ๊นŠ์ˆ™์ด ์ˆจ๊ฒจ๋†“์€ **์ž‘์€ ๊ธˆ๊ณ  ๋ฐ•์Šค(current ์†์„ฑ)**์•ผ.
    ๋„ค๊ฐ€ ๋ชฐ๋ž˜ ๊ธˆ๊ณ  ๋ฌธ์„ ์—ด๊ณ  current ๊ณต๊ฐ„ ์•ˆ์— ๋ˆ์„ 100๋งŒ ์›์œผ๋กœ ๋ฐ”๊พธ๋“  10์›์œผ๋กœ ์ชผ๊ฐœ๋“  ๋™๋„ค ์‚ฌ๋žŒ๋“ค์€ ์•„๋ฌด๋„ ๋ชจ๋ฅด๊ณ  ์•„๋ฌด ์†Œ๋ฆฌ๋„ ์•ˆ ๋‚˜(๋ฆฌ๋ Œ๋”๋ง ๋ฌด์‹œ).
    ํ•˜์ง€๋งŒ ์ปดํฌ๋„ŒํŠธ ๊ด‘์žฅ์ด ์—ฌ๋Ÿฌ ๋ฒˆ ํญ๋ฐœํ•˜๊ณ  ๋‹ค์‹œ ์ƒ๊ฒจ๋„, ๊ทธ ๋ฐ”์ง“๋‹จ ์† ๊ธˆ๊ณ  ์ƒ์ž๋Š” ์ปดํฌ๋„ŒํŠธ๊ฐ€ ์‚ด์•„์žˆ๋Š” ๊ธฐ๊ฐ„ ๋‚ด๋‚ด ์˜๊ตฌ์ ์œผ๋กœ ๋ณด์กด๋˜๋ฉด์„œ ์ ˆ๋Œ€ ์ •๋ณด๊ฐ€ ์ฆ๋ฐœํ•˜์ง€ ์•Š์•„.

โœ… ํ•ต์‹ฌ ์›๋ฆฌ:
๋ฆฌ์•กํŠธ ์ฝ”์–ด ๊ฐœ๋ฐœ์ž๋“ค์˜ ๋จธ๋ฆฌํ†ต์„ ๋œฏ์–ด๋ณด๋ฉด ์ด๋ ‡๊ฒŒ ์„ค๊ณ„๋˜์–ด ์žˆ์Šต๋‹ˆ๋‹ค.
์‚ฌ์‹ค useRef ๋‚ด๋ถ€ ์ฝ”๋“œ๋Š” ์ž๋ฐ”์Šคํฌ๋ฆฝํŠธ์˜ ๋‹จ์ˆœํ•œ ๊ผผ์ˆ˜์ž…๋‹ˆ๋‹ค. useState({ current: initialValue })๋ผ๊ณ  ์„ธํŒ…ํ•ด๋‘๊ณ  ๊ทธ setter ํ•จ์ˆ˜๋ฅผ ํ‰์ƒ ์ ˆ.๋Œ€ ์ œ๊ณตํ•˜์ง€ ์•Š์•„์„œ, ๋ฐ”๊ตฌ๋‹ˆ ์ฃผ์†Œ๊ฐ’์ด ์ปดํฌ๋„ŒํŠธ ์ƒ์•  ๋‚ด๋‚ด **์ฒ ๋ฒฝ ๋ฐฉ์–ด ๋ ˆํผ๋Ÿฐ์Šค(๋ถˆ๋ณ€ ์ฃผ์†Œ)**๋กœ ์œ ์ง€๋˜๊ฒŒ ๋งŒ๋“ค์–ด๋†“์€ ๊ฒƒ์ž…๋‹ˆ๋‹ค!
(ํ™”๋ฉด UI ํŒŒ์ดํ”„๋ผ์ธ๊ณผ ์™„๋ฒฝํžˆ ๊ฒฉ๋ฆฌ๋œ, ํƒˆ(่„ซ)๋ฆฌ์•กํŠธ ์ƒํƒœ๊ณ„์˜ ์Šค์œ„์Šค ์€ํ–‰ ๋น„๋ฐ€ ๊ธˆ๊ณ ์ฃ .)


๐Ÿงฉ ์‹ค์ „ ๋ฌด๊ธฐํ™”: ์ˆจ๊ฒจ์ง„ ๋ณ€์ˆ˜๋“ค ๋‹ค๋ฃจ๊ธฐ

โœ… ์˜ํ˜ธ์˜ ์™„๋ฒฝํ•œ ๋ฆฌํŒฉํ† ๋ง: current ๋ฌด๊ธฐ๊ณ  ์‚ฌ์šฉ

  1. UI(ํ™”๋ฉด)์— ๊ทธ๋ฆด ๋‚ด์šฉ์€ -> ๋ Œ๋”๋ง์— ๋ฐ˜์‘ํ•˜๋Š” useState ๋งˆ์ดํฌ์— ๋‹ด๋Š”๋‹ค (seconds)
  2. ๋‚ด๋ถ€ ๋กœ์ง ํ†ต์ œ์šฉ(์•Œ๋žŒ, ํƒ€์ด๋จธ ์•„์ด๋””, ๋“œ๋ž˜๊ทธ ์Šคํฌ๋กค ํ”ฝ์…€ ์ด์ „ ์œ„์น˜ ๋“ฑ) ๋ฐฑ๊ทธ๋ผ์šด๋“œ ๋ฐ์ดํ„ฐ๋Š” -> ๋น„๋ฐ€ ๊ธˆ๊ณ  useRef์— ๋‹ด์•„ ๋ชฐ๋ž˜ ๊ด€๋ฆฌํ•œ๋‹ค (timerRef)
// โœ… ์šฐ์•„ํ•œ ๊ณ ์„ฑ๋Šฅ ๋ Œ๋”๋ง ์ฝ”๋“œ (Pro Approach)
function Stopwatch() {
  const [seconds, setSeconds] = useState(0); // ํ™”๋ฉด UI์™€ ์ง๊ฒฐ๋œ ์œ ์ผํ•œ ์นœ๊ตฌ
  const timerRef = useRef(null); // ๐ŸŽฏ ๋ฆฌ๋ Œ๋”๋ง ๊ฐ์‹œ ๋ฉด์ œ๊ถŒ ๋ฐœ๊ธ‰!
 
  const handleStart = () => {
    if (timerRef.current) return; // ์ด๋ฏธ ๋Œ๊ณ  ์žˆ์œผ๋ฉด ๋ฐฉ์–ด!
    
    // ์ด ๊ฐ’์„ ๊ฐฑ์‹ ํ•ด๋„ ๋ฆฌ์•กํŠธ๋Š” ๋ˆˆ๋„ ๊นœ์ง ์•ˆ ํ•ฉ๋‹ˆ๋‹ค. ๋ถˆํ•„์š”ํ•œ ๋ Œ๋”๋ง 0ํšŒ ๋‹ฌ์„ฑ.
    timerRef.current = setInterval(() => setSeconds(s => s + 1), 1000);
  };
 
  const handleStop = () => {
    clearInterval(timerRef.current);
    timerRef.current = null; // ์ดˆ๊ธฐํ™”
  };
 
  return (
    <div>
      <p>๊ฒฝ๊ณผ ์‹œ๊ฐ„: {seconds}์ดˆ</p>
      <button onClick={handleStart}>์‹œ์ž‘</button>
      <button onClick={handleStop}>๋ฉˆ์ถฐ!</button>
    </div>
  );
}

๊น”๋”ํ•ฉ๋‹ˆ๋‹ค. setTimerId(id) ๊ฐ™์€ ๋น„ํšจ์œจ์ด ๋ชจ์กฐ๋ฆฌ ํŒŒ๊ดด๋˜์—ˆ์–ด.
timerRef.current = ... ํ• ๋‹น๋ฌธ์€ ๊ทธ์ € ์ˆœ์ˆ˜ํ•œ ๋ฐ”๋‹๋ผ ์ž๋ฐ”์Šคํฌ๋ฆฝํŠธ ์ฝ”๋“œ๊ฐ€ ๋„๋Š” ๊ฒƒ๊ณผ ๋˜‘๊ฐ™์€ ๋‚ ๋ ตํ•œ ์ˆ˜์ค€์˜ ์†๋„๋ฅผ ๋ณด์žฅํ•ฉ๋‹ˆ๋‹ค.


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

โŒ useRef ๊ธˆ๊ณ  ์•ˆ์˜ ๊ฐ’์„ ํ™”๋ฉด์— ๋…ธ์ถœ์‹œํ‚ค๋Š” ์‚ฌ์ƒ๋ˆ„๊ฐ

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

const countRef = useRef(0);
 
const handleAdd = () => {
  countRef.current += 1;
  // ๐Ÿ’ฅ ์˜์ฒ : "ํžˆํžˆ ๋ˆŒ๋ €๋Š”๋ฐ ํ™”๋ฉด ์ˆซ์ž๊ฐ€ ์•ˆ ๋ฐ”๋€Œ์ž–์•„์š”!"
};
 
// ... <button onClick={handleAdd}>๋‚˜๋น„ ๋ˆ„๋ฆ„ ํšŸ์ˆ˜: {countRef.current}</button> ...

์›์ธ: useRef๊ฐ€ ๋ Œ๋”๋ง์„ ๋ฐœ๋™์‹œํ‚ค์ง€ ์•Š๋Š”๋‹ค(ํƒˆ-๋ฆฌ์•กํŠธ ์„ฑ์งˆ)๋Š” ๊ฒƒ์„ ์ธ์ง€ํ•˜์ง€ ๋ชปํ•˜๊ณ  ์–ต์ง€๋กœ ํ™”๋ฉด UI ํ”ฝ์…€(JSX ๋ฐ˜ํ™˜ ๊ณต๊ฐ„)์— ์‘ค์…” ๋„ฃ์€ ๊ฑฐ์•ผ. ๋ฆฌ์•กํŠธ๋Š” ๋„ค๊ฐ€ ๋ฒ„ํŠผ์„ ๋ˆŒ๋Ÿฌ์„œ current์— 500์„ ์‘ค์…” ๋„ฃ๋“  100์„ ์‘ค์…” ๋„ฃ๋“  "์–ด์ฉŒ๋ผ๊ณ ? ๋‚˜ํ•œํ…Œ ๋ Œ๋”๋งํ•˜๋ผ๊ณ (setState) ์‹ ํ˜ธ ์•ˆ ์คฌ์ž–์•„?" ํ•˜๋ฉฐ ํƒœ์—…ํ•ด๋ฒ„๋ฆฌ์ง€.
๊ทธ๋Ÿฌ๋‹ค๊ฐ€ ์šฐ์—ฐํžˆ ์˜†์— ์žˆ๋˜ ๋‹ค๋ฅธ ์ƒํƒœ(State)๊ฐ€ setState๋˜์–ด ์ปดํฌ๋„ŒํŠธ๊ฐ€ ๋ฆฌ๋ Œ๋”๋ง์„ ํ•œ ๋ฐ”ํ€ด ๋Œ๋ฉด... ๋†€๋ž๊ฒŒ๋„ ์•„๊นŒ ์Œ“์•„๋‘” 500์ด๋ผ๋Š” ๋ˆ„๋ฆ„ ํšŸ์ˆ˜๊ฐ€ ์˜๊ตฌ๋ณด์กด๋˜์–ด ์žˆ๋‹ค๊ฐ€ ๊ทธ์ œ์•ผ ๊ฐ‘์ž๊ธฐ ํ™”๋ฉด์— ํŒ! ํ•˜๊ณ  ํŠ€์–ด๋‚˜์˜ต๋‹ˆ๋‹ค(๋ฐ€๋ฆฐ ๋ Œ๋”๋ง). ์‚ฌ์šฉ์ž๋Š” ๊ทน๋„์˜ ํ˜ผ๋ž€์„ ๊ฒช์ฃ .

ํ•ด๊ฒฐ์ฑ…:
์ ˆ๋Œ€๋กœ!! useRef์˜ current ์†์„ฑ๊ฐ’์„ ๋ Œ๋”๋ง ๊ฒฐ๊ณผ๋ฌผ(<p>{์—ฌ๊ธฐ}</p>) ์•ˆ์—๋‹ค ์จ์„œ ๋„์šฐ์ง€ ๋งˆ์„ธ์š”. UI์™€ ์ง๊ฒฐ๋˜๋Š” ๋ฐ์ดํ„ฐ๋ผ๋ฉด ๋ฐ˜๋“œ์‹œ useState๋ฅผ ๊ณ ๋ฅด์‹ญ์‹œ์˜ค.
"๋ฐ์ดํ„ฐ์˜ ๋ณ€๊ฒฝ์ด ์‹œ๊ฐ์ ์ธ ๋ณ€ํ™”๋ฅผ ๋‚ณ๋Š”๊ฐ€?" -> YES๋ฉด State, NO๋ฉด Ref์ž…๋‹ˆ๋‹ค.


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

๋„๊ตฌ์˜ ๋ณธ์งˆuseState (๋งˆ์ดํฌ)useRef (๋น„๋ฐ€ ๊ธˆ๊ณ )
๋ฐ์ดํ„ฐ๋ฅผ ์ˆ˜์ •ํ•˜๋ฉด?์ฆ‰์‹œ ๋ฆฌ๋ Œ๋”๋ง ๋ฐœ์ƒ (UI ์—…๋ฐ์ดํŠธ O)๋ฆฌ๋ Œ๋”๋ง ๋ฐœ์ƒ ์•ˆ ํ•จ (ํ™”๋ฉด ์–ผ์–ด์žˆ์Œ X)
๋ Œ๋”๋ง ๊ฐ„ ๋ฐ์ดํ„ฐ ์œ ์ง€O (ํ•˜์ง€๋งŒ ๋ Œ๋”๋ง๋งˆ๋‹ค ๊ฐ’์„ ์Šค๋ƒ…์ƒท ๊ณ ์ • ๋ณต์‚ฌํ•ด ์คŒ)O (์–ธ์ œ ๊ฐ€๋ฆฌ์ผœ๋„ '๋™์ผํ•œ ์ตœ์‹  ์ฃผ์†Œ ํž™ ๋ฒ„ํผ' ์ฐธ์กฐ)
์–ด๋””์— ์–ด์šธ๋ฆฌ๋Š”๊ฐ€?์ธํ’‹ ์ž…๋ ฅ ํ…์ŠคํŠธ, ๋ชจ๋‹ฌ์ฐฝ(T/F), ๋ฒ„ํŠผ ์ปฌ๋Ÿฌ ๋“ฑ ํ™”๋ฉด ๊ทธ๋ฆด ๋•Œํƒ€์ด๋จธ ์•„์ด๋”” ์ฅ๊ธฐ, DOM ์š”์†Œ ํฌ์ปค์Šค ์กฐ์ž‘ํ•˜๊ธฐ, ์ด์ „(Prev) ๊ฐ’ ๋ชฐ๋ž˜ ์ €์žฅํ•˜๊ธฐ ๋“ฑ

๐Ÿ’ก ํ•œ ์ค„๋กœ ๊ธฐ์–ตํ•˜๊ธฐ
**"๋‚˜๋งŒ์˜ ์ด ์†Œ์ค‘ํ•œ ๋ฐ์ดํ„ฐ๊ฐ€ ๋ฐ”๋€Œ์—ˆ์„ ๋•Œ, ์˜จ ๋งˆ์„์„ ๋’ค์ง‘์–ด์—Ž๊ณ  ํ™”๋ฉด์„ ์ƒˆ๋กœ๊ณ ์นจํ•˜๊ณ  ์‹ถ์€๊ฐ€?"**์ด ๋ฌธํ•ญ์— "์•„๋‹ˆ์š”, ๊ทธ๋ƒฅ ๋ฐ์ดํ„ฐ ์ˆซ์ž๋งŒ ํ˜ผ์ž ๊ธฐ์–ตํ•ด์ฃผ๋ฉด ๋ผ์š”."๋ผ๊ณ  ์™ธ์น˜๊ณ  ์‹ถ๋‹ค๋ฉด ๋ฌด์กฐ๊ฑด ๋ง์„ค์ด์ง€ ๋ง๊ณ  useRef ์•ˆ์ฃผ๋จธ๋‹ˆ๋ฅผ ์งœ๋ผ.


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

ํ™”๋ฉด์— ๊ทธ๋ฆฌ์ง€๋„ ์•Š์„ ํƒ€์ด๋จธ ์•„์ด๋””๋กœ ๋ฌด์˜๋ฏธํ•œ ๋ Œ๋”๋ง ํญํƒ„์„ ๋‚ ๋ฆฌ๊ณ  ์žˆ์—ˆ๋‹ค๋‹ˆ, useRef๊ฐ€ ๋‹จ์ˆœํžˆ ํฌ์ปค์Šค ์žก๋Š” ์šฉ๋„๊ฐ€ ์•„๋‹ˆ๋ผ '์•ˆ์ฃผ๋จธ๋‹ˆ ๋น„๋ฐ€ ๊ธˆ๊ณ '๋ผ๋Š” ๋น„์œ ๊ฐ€ ํ•ต์‹ฌ์„ ๊ด€ํ†ตํ–ˆ๋‹ค.

๐Ÿ’ก "์ƒํƒœ(State)๋Š” ๋งˆ์ดํฌ, ์ฐธ์กฐ(Ref)๋Š” ๋น„๋ฐ€ ๊ธˆ๊ณ . ๋ฐ์ดํ„ฐ๊ฐ€ ๋ณ€ํ•  ๋•Œ ํ™”๋ฉด ํ”ฝ์…€์ด ๋ฐ”๋€Œ์–ด์•ผ ํ•˜๋Š”์ง€ ํ•œ ๋ฒˆ๋งŒ ์ƒ๊ฐํ•ด๋ณด์ž!"

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


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

Q1. useState ๋Œ€์‹  useRef๋ฅผ ์„ ํƒํ•˜๋Š” ๊ฒƒ์ด ๊ฐ€์žฅ ์™„๋ฒฝํ•œ ๋ฒ ์ŠคํŠธ ํ”„๋ž™ํ‹ฐ์Šค(Best Practice)๋กœ ๋ถ€ํ•ฉํ•˜๋Š” ์ƒํ™ฉ์„ ํ•˜๋‚˜ ๊ณ ๋ฅด์„ธ์š”.

  • A) ์‚ฌ์šฉ์ž๊ฐ€ ์‡ผํ•‘๋ชฐ ๊ฒ€์ƒ‰์ฐฝ์—์„œ ํƒ€์ดํ•‘ํ•˜๊ณ  ์žˆ๋Š” ์‹ค์‹œ๊ฐ„ ๊ฒ€์ƒ‰์–ด ํ…์ŠคํŠธ ๊ฐ’์„ ์œ ์ง€ํ•˜๊ณ  ์‹ถ์„ ๋•Œ.
  • B) ํ˜„์žฌ ๋กœ๊ทธ์ธํ•œ ํ† ํฐ์ด ์œ ํšจํ•œ ์œ ์ €์ธ์ง€์— ๋Œ€ํ•œ boolean(T/F) ๊ฐ’์„ ์ €์žฅํ•˜๊ณ  ๊ถŒํ•œ ์—๋Ÿฌ ๋ชจ๋‹ฌ์„ ๋„์šธ ๋•Œ.
  • C) ์ปดํฌ๋„ŒํŠธ ๋งˆ์šดํŠธ ์ดํ›„ 30์ดˆ ๋™์•ˆ ์•„๋ฌด ํด๋ฆญ๋„ ํ•˜์ง€ ์•Š์œผ๋ฉด ๊ฒฝ๊ณ  ํŒ์—…์„ ๋„์›Œ์ค„ setTimeout ํ•จ์ˆ˜์˜ ์˜ˆ์•ฝ ๊ณ ์œ  ํ†ต์ œ ์•„์ด๋””(ID)๋ฅผ ์ €์žฅํ•  ๋•Œ.
  • D) ์‚ฌ์šฉ์ž์˜ ํ˜„์žฌ ์‡ผํ•‘ ์นดํŠธ์— ๋‹ด๊ธด ๋ฌผํ’ˆ ์ด ๊ฒฐ์ œ ๊ธˆ์•ก์„ ์‹ค์‹œ๊ฐ„ ๊ณ„์‚ฐํ•˜์—ฌ ์šฐ์ธก ํ•˜๋‹จ ์˜์ˆ˜์ฆ์— ๋ณด์—ฌ์ค„ ๋•Œ.

โœ… ์ •๋‹ต: C

๐Ÿ’ก ์ƒ์„ธ ํ•ด์„ค: ๋ Œ๋”๋ง ํŠธ๋ฆฌ๊ฑฐ ์—ฌ๋ถ€๋งŒ ๊ตฌ์ƒํ•  ์ค„ ์•Œ๋ฉด ๋ฉ๋‹ˆ๋‹ค! A์˜ ๊ฒ€์ƒ‰์–ด, B์˜ ๋ชจ๋‹ฌ T/F, D์˜ ์นดํŠธ ๊ฒฐ์ œ์•ก ์ˆซ์ž๋Š” ์ „๋ถ€ "๊ฐ’์ด ํ•œ ๋ฒˆ์ด๋ผ๋„ ๋ฐ”๋€Œ๋ฉด ํ™”๋ฉด์˜ ํ”ฝ์…€ UI๊ฐ€ ์œ ์ € ๋ˆˆ์•ž์—์„œ ์ฆ‰์‹œ์ฆ‰์‹œ ๋ณ€๊ฒฝ๋˜์–ด์•ผ ํ•˜๋Š”" UI ์ง๊ฒฐํ˜• ๋ฐ์ดํ„ฐ์ด๋ฏ€๋กœ ๋ฌด์กฐ๊ฑด useState์˜ ์˜์—ญ์ž…๋‹ˆ๋‹ค.
๋ฐ˜๋ฉด C์˜ ํƒ€์ด๋จธ ์•„์ด๋””๋Š” ๋‹จ์ˆœ ์ •์ˆ˜ ์ˆซ์ž(1, 2, 3...)์ผ ๋ฟ ๋ธŒ๋ผ์šฐ์ € DOM ์–ด๋””์—๋„ ์ถœ๋ ฅ๋  ์ผ์ด ์—†์œผ๋ฉฐ, ์˜ค์ง ํด๋ฆฐ์—… ์‹œ clearTimeout(ID) ์ฒ˜๋ฆฌ ๋กœ์ง์„ ํ†ต์ œํ•˜๊ธฐ ๋’ท๊ตฌ๋ฉ ๋ฐ์ดํ„ฐ์ด๋ฏ€๋กœ ๋ฆฌ์•กํŠธ ์—”์ง„์— ์‹œ๋น„(๋ฆฌ๋ Œ๋”๋ง ๋ถ€๋‹ด)๋ฅผ ๊ฑธ ํ•„์š”๊ฐ€ 1๋„ ์—†๋Š” useRef์˜ ์ตœ์  ๋ฌด๋Œ€์ž…๋‹ˆ๋‹ค.

Q2. ๋‹ค์Œ ์ค‘ ์˜์ฒ ์ด๊ฐ€ ์ง  useRef ์กฐ์ž‘์— ๋Œ€ํ•ด, ๋ฆฌ์•กํŠธ ํ•ต์‹ฌ ํŒ€ ๋™๋ฃŒ๊ฐ€ ๊ฐ€์žฅ ๊ฒฝ์•…(Horrify)ํ•˜๊ณ  ์ฝ”๋“œ ๋ฆฌ๋ทฐ ์‹œ ๋ฐ”๋กœ ๋น ๊พธ(Reject)๋ฅผ ๋จน์ผ ์น˜๋ช…์  ํŒจํ„ด์€ ๋ฌด์—‡์ธ๊ฐ€์š”?

  • A) <input ref={myInputRef} /> ํ˜•ํƒœ๋กœ DOM ์š”์†Œ์— ์ง์ ‘ ๊ฐˆ๊ณ ๋ฆฌ๋ฅผ ๋˜์ง„ ๊ฒƒ.
  • B) useEffect ์™ธ๋ถ€ ํด๋ฆฐ์—… ๊ณต๊ฐ„์—์„œ myRef.current = null๋กœ ์ดˆ๊ธฐํ™”ํ•œ ๊ฒƒ.
  • C) <div>๋‚ด ๋น„๋ฐ€ ๊ธˆ๊ณ : {secretRef.current}</div> ํ˜•ํƒœ๋กœ JSX ๋ Œ๋”๋ง ๋ฐ˜ํ™˜ ๊ณต๊ฐ„์•ˆ์— ๋ณ€์ˆ˜๋ฅผ ๋ฐ•์•„๋‘” ๊ฒƒ.
  • D) ์™ธ๋ถ€ ํ™˜๊ฒฝ์— const initial = 'abc'๋ฅผ ๋นผ๋‘๊ณ  useRef(initial)๋กœ ๊ฐ’์„ ์ดˆ๊ธฐ ์„ธํŒ…ํ•œ ๊ฒƒ.

โœ… ์ •๋‹ต: C

๐Ÿ’ก ์ƒ์„ธ ํ•ด์„ค: ์ ˆ๋Œ€ ๊ธˆ๊ธฐ์‚ฌํ•ญ(Antipattern)์ž…๋‹ˆ๋‹ค! useRef๋Š” ํƒœ์ƒ๋ถ€ํ„ฐ "๋ฆฌ์•กํŠธ์˜ ํ†ต์ œ ๋ฐ–(๋ Œ๋”๋ง ํŠธ๋ฆฌ๊ฑฐ ๊ธฐ๋Šฅ ๊ฑฐ์„ธ๋จ)"์— ์กด์žฌํ•˜๋Š” ๋น„๋ฐ€ ์ƒ์ž์ธ๋ฐ, ์ด๊ฑธ ์–ต์ง€๋กœ ํ™”๋ฉด์— ๊ทธ๋ ค๋‹ฌ๋ผ๊ณ  ๋„˜๊ฒจ์ฃผ๋ฉด ๊ฐœ๋ฐœ์ž์™€ ํ”„๋ ˆ์ž„์›Œํฌ ๊ฐ„์˜ ์‹ ๋ขฐ๊ฐ€ ๋ฐ•์‚ด๋‚ฉ๋‹ˆ๋‹ค. ๊ฐ’์„ ๋ฐฑ๋‚  ์ฒœ๋‚  ๋’ค์—์„œ ๋ชฐ๋ž˜ ๋ฐ”๊ฟ”๋ดค์ž ๋ฆฌ์•กํŠธ๋Š” ๋ฆฌ๋ Œ๋”๋งํ•ด์ฃผ์ง€ ์•Š์œผ๋ฏ€๋กœ ์‚ฌ์šฉ์ž๋Š” ๋‚ก์€ ํ™”๋ฉด์„ ๋ณด๊ฒŒ ๋˜๋ฉฐ, ์ปดํฌ๋„ŒํŠธ์˜ ์ƒ๋ช…์ฃผ๊ธฐ๋ฅผ ์™„๋ฒฝํžˆ ํ˜ผ๋ž€์— ๋น ๋œจ๋ฆฌ๋Š” ๋ฒ„๊ทธ ๋จธ์‹ ์„ ๋‚ณ๊ฒŒ ๋ฉ๋‹ˆ๋‹ค. (A๋Š” ๊ธฐ๋ณธ ์‚ฌ์šฉ๋ฒ•, B์™€ D๋Š” ์ •์ƒ ์‚ฌ์šฉ๋ฒ•).

Q3. ์ฃผ๊ด€์‹ ๋…ผ์ˆ : useRef๊ฐ€ ์ปดํฌ๋„ŒํŠธ์˜ ๋ Œ๋”๋ง ํšŸ์ˆ˜(์žฌ์‹คํ–‰)์— ๊ด€๊ณ„์—†์ด ์–ด๋–ป๊ฒŒ ํ•ญ์ƒ "๋‹จ ํ•˜๋‚˜์˜ ์˜จ์ „ํ•œ ํ†ต(๋ฐ•์Šค)"์„ ๊ธฐ์–ตํ•˜๊ณ  ์˜๊ตฌ ๋ถˆ๋ณ€ํ•˜๊ฒŒ ์ €์žฅํ•˜๋Š” ๊ตฌ์กฐ๋ฅผ ๋ฆฌ์•กํŠธ ๋‚ด๋ถ€์—์„œ ํ‰๋‚ด(๊ตฌํ˜„) ๋‚ด์—ˆ์„์ง€, useState ๊ฐœ๋…์„ ๋น—๋Œ€์–ด ๊ทธ ๋น„๋ฐ€์˜ ์ž‘๋™ ์›๋ฆฌ๋ฅผ ์„œ์ˆ ํ•˜์‹œ์˜ค.

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

๋‚ด๋ถ€ ์ž‘๋™ ์›๋ฆฌ: ๋ฆฌ์•กํŠธ์˜ useRef๋Š” ์‚ฌ์‹ค ์™ธ๊ณ„ ๊ธฐ์ˆ ์ด ์•„๋‹™๋‹ˆ๋‹ค. ์ด๋†ˆ์˜ ๋‚ด๋ถ€๋Š” ์ฒ ์ €ํ•˜๊ฒŒ useState์™€ ๋˜‘๊ฐ™์ด "์ดˆ๊ธฐ๊ฐ’ ์ €์žฅ ๋กœ์ง"์„ ๊ธฐ๋ฐ˜์œผ๋กœ ๊น”๊ณ  ์žˆ์Šต๋‹ˆ๋‹ค. ์†Œ์Šค์ฝ”๋“œ ๋‚ด๋ถ€๋ฅผ ์—ด์–ด๋ณด๋ฉด ๋Œ€๋žต useState({ current: initialValue })[0] ์ฝ”๋“œ๋ฅผ ๋˜์ ธ์ฃผ๋Š” ๊ฒƒ๊ณผ ๋งค์ปค๋‹ˆ์ฆ˜์ด ์™„์ „ํžˆ ๋˜‘๊ฐ™์ฃ .
๊ฐ€์žฅ ํฐ ํ•ต์‹ฌ์€ **"์ƒํƒœ๋ฅผ ๋ฐ”๊ตฌ๋‹ˆ({ current: ... }์ธ ์ž๋ฐ”์Šคํฌ๋ฆฝํŠธ ๊ฐ์ฒด) ๊ป๋ฐ๊ธฐ์— ๊ฐ์‹ธ์„œ ๋‹จ ํ•œ ๋ฒˆ ๋„˜๊ฒจ์ฃผ๊ณ ๋Š”, ๊ทธ ์ƒํƒœ๋ฅผ ๋ณ€๊ฒฝ์‹œํ‚ค๋Š” ๋ฐฉ๋ฒ•์ธ Setter ํ•จ์ˆ˜(setState)๋ฅผ ์™ธ๋ถ€ ์„ธ๊ณ„(๊ฐœ๋ฐœ์ž)์— ์ ˆ๋Œ€ ๋…ธ์ถœ ์ œ๊ณตํ•˜์ง€ ์•Š๋Š”๋‹ค"**๋Š” ๊ฒƒ์ž…๋‹ˆ๋‹ค.
๊ฒฐ๊ตญ ๊ฐœ๋ฐœ์ž๋Š” ์ด ์ž๋ฐ”์Šคํฌ๋ฆฝํŠธ ๊ฐ์ฒด(Object)์˜ "์ฃผ์†Œ(Reference)" ํ•˜๋‚˜๋งŒ ํ‰์ƒ ๊ณต์œ ๋ฐ›์œผ๋ฉฐ, ๊ทธ ์ฃผ์†Œ ์•ˆ์˜ ๋‚ด์šฉ๋ฌผ(Property)์ธ current๋งŒ ์ฃผ๊ตฌ์žฅ์ฐฝ ์ง์ ‘ ์‘ค์…”์„œ ๋ณ€์น™ ์กฐ์ž‘ํ•˜๊ฒŒ ๋ฉ๋‹ˆ๋‹ค. ๊ฐ์ฒด ์ฃผ์†Œ๋Š” ๋งŒ๋…„ ๊ฐ™์œผ๋ฏ€๋กœ ๋ฆฌ์•กํŠธ๋Š” ์˜์›ํžˆ ๋ฆฌ๋ Œ๋”๋ง์„ ์ผ์œผํ‚ค์ง€ ์•Š๊ณ , ๋‚ด์šฉ๋ฌผ์€ ๋ฌด์‚ฌํžˆ ์‚ด์•„๋‚จ๋Š” ์™„๋ฒฝํ•œ ํƒˆ์ถœ๊ตฌ๊ฐ€ ๋˜๋Š” ๊ฒƒ์ด์ฃ .