useRef๋Š” ๋ Œ๋”๋ง์— ํ•„์š”ํ•˜์ง€ ์•Š์€ ๊ฐ’์„ ์ฐธ์กฐํ•  ์ˆ˜ ์žˆ๋Š” React Hook์ž…๋‹ˆ๋‹ค.

const ref = useRef(initialValue)

๋ ˆํผ๋Ÿฐ์Šค

useRef(initialValue)

์ปดํฌ๋„ŒํŠธ์˜ ์ตœ์ƒ์œ„ ๋ ˆ๋ฒจ์—์„œ useRef๋ฅผ ํ˜ธ์ถœํ•˜์—ฌ ref๋ฅผ ์„ ์–ธํ•ฉ๋‹ˆ๋‹ค.

import { useRef } from 'react';

function MyComponent() {
const intervalRef = useRef(0);
const inputRef = useRef(null);
// ...

์•„๋ž˜์—์„œ ๋” ๋งŽ์€ ์˜ˆ์‹œ๋ฅผ ํ™•์ธํ•˜์„ธ์š”.

๋งค๊ฐœ๋ณ€์ˆ˜

  • initialValue: ref ๊ฐ์ฒด์˜ currentํ”„๋กœํผํ‹ฐ ์ดˆ๊ธฐ ์„ค์ •๊ฐ’์ž…๋‹ˆ๋‹ค. ์—ฌ๊ธฐ์—๋Š” ์–ด๋–ค ์œ ํ˜•์˜ ๊ฐ’์ด๋“  ์ง€์ •ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ์ด ์ธ์ž๋Š” ์ดˆ๊ธฐ ๋ Œ๋”๋ง ์ดํ›„๋ถ€ํ„ฐ๋Š” ๋ฌด์‹œ๋ฉ๋‹ˆ๋‹ค.

๋ฐ˜ํ™˜๊ฐ’

useRef๋Š” ๋‹จ์ผ ํ”„๋กœํผํ‹ฐ๋ฅผ ๊ฐ€์ง„ ๊ฐ์ฒด๋ฅผ ๋ฐ˜ํ™˜ํ•ฉ๋‹ˆ๋‹ค:

  • current: ์ฒ˜์Œ์—๋Š” ์ „๋‹ฌํ•œ initialValue๋กœ ์„ค์ •๋ฉ๋‹ˆ๋‹ค. ๋‚˜์ค‘์— ๋‹ค๋ฅธ ๊ฐ’์œผ๋กœ ๋ฐ”๊ฟ€ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ref ๊ฐ์ฒด๋ฅผ JSX ๋…ธ๋“œ์˜ ref์–ดํŠธ๋ฆฌ๋ทฐํŠธ๋กœ React์— ์ „๋‹ฌํ•˜๋ฉด React๋Š” currentํ”„๋กœํผํ‹ฐ๋ฅผ ์„ค์ •ํ•ฉ๋‹ˆ๋‹ค.

๋‹ค์Œ ๋ Œ๋”๋ง์—์„œ useRef๋Š” ๋™์ผํ•œ ๊ฐ์ฒด๋ฅผ ๋ฐ˜ํ™˜ํ•ฉ๋‹ˆ๋‹ค.

์ฃผ์˜์‚ฌํ•ญ

  • ref.current ํ”„๋กœํผํ‹ฐ๋Š” state์™€ ๋‹ฌ๋ฆฌ ๋ณ€์ดํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ๊ทธ๋Ÿฌ๋‚˜ ๋ Œ๋”๋ง์— ์‚ฌ์šฉ๋˜๋Š” ๊ฐ์ฒด(์˜ˆ: state์˜ ์ผ๋ถ€)๋ฅผ ํฌํ•จํ•˜๋Š” ๊ฒฝ์šฐ ํ•ด๋‹น ๊ฐ์ฒด๋ฅผ ๋ณ€์ดํ•ด์„œ๋Š” ์•ˆ ๋ฉ๋‹ˆ๋‹ค.
  • ref.current ํ”„๋กœํผํ‹ฐ๋ฅผ ๋ณ€๊ฒฝํ•ด๋„ React๋Š” ์ปดํฌ๋„ŒํŠธ๋ฅผ ๋‹ค์‹œ ๋ Œ๋”๋งํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค. ref๋Š” ์ผ๋ฐ˜ JavaScript ๊ฐ์ฒด์ด๊ธฐ ๋•Œ๋ฌธ์— React๋Š” ์‚ฌ์šฉ์ž๊ฐ€ ์–ธ์ œ ๋ณ€๊ฒฝํ–ˆ๋Š”์ง€ ์•Œ์ง€ ๋ชปํ•ฉ๋‹ˆ๋‹ค.
  • ์ดˆ๊ธฐํ™”๋ฅผ ์ œ์™ธํ•˜๊ณ ๋Š” ๋ Œ๋”๋ง ์ค‘์— ref.current๋ฅผ ์“ฐ๊ฑฐ๋‚˜ ์ฝ์ง€ ๋งˆ์„ธ์š”. ์ด๋ ‡๊ฒŒ ํ•˜๋ฉด ์ปดํฌ๋„ŒํŠธ์˜ ๋™์ž‘์„ ์˜ˆ์ธกํ•  ์ˆ˜ ์—†๊ฒŒ ๋ฉ๋‹ˆ๋‹ค.
  • Strict Mode์—์„œ React๋Š” ์ปดํฌ๋„ŒํŠธ ํ•จ์ˆ˜๋ฅผ ๋‘ ๋ฒˆ ํ˜ธ์ถœํ•˜์—ฌ ์˜๋„ํ•˜์ง€ ์•Š์€ ๋ถˆ์ˆœ๋ฌผ์„ ์ฐพ์„ ์ˆ˜ ์žˆ๋„๋ก ๋•์Šต๋‹ˆ๋‹ค. ์ด๋Š” ๊ฐœ๋ฐœ ํ™˜๊ฒฝ ์ „์šฉ ๋™์ž‘์ด๋ฉฐ ์ƒ์šฉ ํ™˜๊ฒฝ์—๋Š” ์˜ํ–ฅ์„ ๋ฏธ์น˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค. ๊ฐ ref ๊ฐ์ฒด๋Š” ๋‘ ๋ฒˆ ์ƒ์„ฑ๋˜๊ณ  ๊ทธ์ค‘ ํ•˜๋‚˜๋Š” ๋ฒ„๋ ค์ง‘๋‹ˆ๋‹ค. ์ปดํฌ๋„ŒํŠธ ํ•จ์ˆ˜๊ฐ€ ์ˆœ์ˆ˜ํ•˜๋‹ค๋ฉด(๊ทธ๋ž˜์•ผ๋งŒ ํ•ฉ๋‹ˆ๋‹ค), ์ปดํฌ๋„ŒํŠธ์˜ ๋กœ์ง์— ์˜ํ–ฅ์„ ๋ฏธ์น˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค.

์‚ฌ์šฉ๋ฒ•

ref๋กœ ๊ฐ’ ์ฐธ์กฐํ•˜๊ธฐ

์ปดํฌ๋„ŒํŠธ์˜ ์ตœ์ƒ์œ„ ๋ ˆ๋ฒจ์—์„œ useRef๋ฅผ ํ˜ธ์ถœํ•˜์—ฌ ํ•˜๋‚˜ ์ด์ƒ์˜ ref๋ฅผ ์„ ์–ธํ•ฉ๋‹ˆ๋‹ค.

import { useRef } from 'react';

function Stopwatch() {
const intervalRef = useRef(0);
// ...

useRef๋Š” ์ฒ˜์Œ์— ์ œ๊ณตํ•œ ์ดˆ๊ธฐ๊ฐ’์œผ๋กœ ์„ค์ •๋œ ๋‹จ์ผ current ํ”„๋กœํผํ‹ฐ๊ฐ€ ์žˆ๋Š” ref ๊ฐ์ฒด๋ฅผ ๋ฐ˜ํ™˜ํ•ฉ๋‹ˆ๋‹ค.

๋‹ค์Œ ๋ Œ๋”๋ง์—์„œ useRef๋Š” ๋™์ผํ•œ ๊ฐ์ฒด๋ฅผ ๋ฐ˜ํ™˜ํ•ฉ๋‹ˆ๋‹ค. ์ •๋ณด๋ฅผ ์ €์žฅํ•˜๊ณ  ๋‚˜์ค‘์— ์ฝ์„ ์ˆ˜ ์žˆ๋„๋ก current ์†์„ฑ์„ ๋ณ€๊ฒฝํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. state๊ฐ€ ๋– ์˜ค๋ฅผ ์ˆ˜ ์žˆ์ง€๋งŒ, ๋‘˜ ์‚ฌ์ด์—๋Š” ์ค‘์š”ํ•œ ์ฐจ์ด์ ์ด ์žˆ์Šต๋‹ˆ๋‹ค.

ref๋ฅผ ๋ณ€๊ฒฝํ•ด๋„ ๋ฆฌ๋ Œ๋”๋ง์„ ์ด‰๋ฐœํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค. ์ฆ‰ ref๋Š” ์ปดํฌ๋„ŒํŠธ์˜ ์‹œ๊ฐ์  ์ถœ๋ ฅ์— ์˜ํ–ฅ์„ ๋ฏธ์น˜์ง€ ์•Š๋Š” ์ •๋ณด๋ฅผ ์ €์žฅํ•˜๋Š” ๋ฐ ์ ํ•ฉํ•ฉ๋‹ˆ๋‹ค. ์˜ˆ๋ฅผ ๋“ค์–ด interval ID๋ฅผ ์ €์žฅํ–ˆ๋‹ค๊ฐ€ ๋‚˜์ค‘์— ๋ถˆ๋Ÿฌ์™€์•ผ ํ•˜๋Š” ๊ฒฝ์šฐ ref์— ๋„ฃ์„ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ref ๋‚ด๋ถ€์˜ ๊ฐ’์„ ์—…๋ฐ์ดํŠธํ•˜๋ ค๋ฉด current ํ”„๋กœํผํ‹ฐ๋ฅผ ์ˆ˜๋™์œผ๋กœ ๋ณ€๊ฒฝํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค:

function handleStartClick() {
const intervalId = setInterval(() => {
// ...
}, 1000);
intervalRef.current = intervalId;
}

๋‚˜์ค‘์— ref์—์„œ ํ•ด๋‹น interval ID๋ฅผ ์ฝ์–ด ํ•ด๋‹น interval์„ ์ทจ์†Œํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค:

function handleStopClick() {
const intervalId = intervalRef.current;
clearInterval(intervalId);
}

ref๋ฅผ ์‚ฌ์šฉํ•˜๋ฉด ๋‹ค์Œ์„ ๋ณด์žฅํ•ฉ๋‹ˆ๋‹ค:

  • (๋ Œ๋”๋งํ•  ๋•Œ๋งˆ๋‹ค ์žฌ์„ค์ •๋˜๋Š” ์ผ๋ฐ˜ ๋ณ€์ˆ˜์™€ ๋‹ฌ๋ฆฌ) ๋ฆฌ๋ Œ๋”๋ง ์‚ฌ์ด์— ์ •๋ณด๋ฅผ ์ €์žฅํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.
  • (๋ฆฌ๋ Œ๋”๋ง์„ ์ด‰๋ฐœํ•˜๋Š” state ๋ณ€์ˆ˜์™€ ๋‹ฌ๋ฆฌ) ๋ณ€๊ฒฝํ•ด๋„ ๋ฆฌ๋ Œ๋”๋ง์„ ์ด‰๋ฐœํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค.
  • (์ •๋ณด๊ฐ€ ๊ณต์œ ๋˜๋Š” ์™ธ๋ถ€ ๋ณ€์ˆ˜์™€ ๋‹ฌ๋ฆฌ) ๊ฐ๊ฐ์˜ ์ปดํฌ๋„ŒํŠธ์— ๋กœ์ปฌ๋กœ ์ €์žฅ๋ฉ๋‹ˆ๋‹ค.

ref๋ฅผ ๋ณ€๊ฒฝํ•ด๋„ ๋‹ค์‹œ ๋ Œ๋”๋ง๋˜์ง€ ์•Š์œผ๋ฏ€๋กœ ํ™”๋ฉด์— ํ‘œ์‹œ๋˜๋Š” ์ •๋ณด๋ฅผ ์ €์žฅํ•˜๋Š” ๋ฐ๋Š” ref๊ฐ€ ์ ํ•ฉํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค. ๋Œ€์‹  state๋ฅผ ์‚ฌ์šฉํ•˜์„ธ์š”. ๋” ์ž์„ธํ•œ ๋‚ด์šฉ์€ useRef์™€ useState ์ค‘ ์„ ํƒํ•˜๊ธฐ์—์„œ ํ™•์ธํ•˜์„ธ์š”.

useRef๋กœ ๊ฐ’์„ ์ฐธ์กฐํ•˜๋Š” ์˜ˆ์‹œ

์˜ˆ์ œ 1 of 2:
counter ํด๋ฆญํ•˜๊ธฐ

์ด ์ปดํฌ๋„ŒํŠธ๋Š” ref๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ๋ฒ„ํŠผ์ด ํด๋ฆญ๋œ ํšŸ์ˆ˜๋ฅผ ์ถ”์ ํ•ฉ๋‹ˆ๋‹ค. ํด๋ฆญ ํšŸ์ˆ˜๋Š” ์ด๋ฒคํŠธ ํ•ธ๋“ค๋Ÿฌ์—์„œ๋งŒ ์ฝ๊ณ  ์“ฐ๊ธฐ ๋•Œ๋ฌธ์— ์—ฌ๊ธฐ์„œ๋Š” state ๋Œ€์‹  ref๋ฅผ ์‚ฌ์šฉํ•ด๋„ ๊ดœ์ฐฎ์Šต๋‹ˆ๋‹ค.

import { useRef } from 'react';

export default function Counter() {
  let ref = useRef(0);

  function handleClick() {
    ref.current = ref.current + 1;
    alert('You clicked ' + ref.current + ' times!');
  }

  return (
    <button onClick={handleClick}>
      Click me!
    </button>
  );
}

JSX์— {ref.current}๋ฅผ ํ‘œ์‹œํ•˜๋ฉด ํด๋ฆญ ์‹œ ๋ฒˆํ˜ธ๊ฐ€ ์—…๋ฐ์ดํŠธ๋˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค. ref.current๋ฅผ ์„ค์ •ํ•ด๋„ ๋ฆฌ๋ Œ๋”๋ง์„ ์ด‰๋ฐœํ•˜์ง€ ์•Š๊ธฐ ๋•Œ๋ฌธ์ž…๋‹ˆ๋‹ค. ๋ Œ๋”๋ง์— ์‚ฌ์šฉํ•˜๋Š” ์ •๋ณด๋Š” ref๊ฐ€ ์•„๋‹Œ state์—ฌ์•ผ ํ•ฉ๋‹ˆ๋‹ค.

์ฃผ์˜ํ•˜์„ธ์š”!

๋ Œ๋”๋ง ์ค‘์—๋Š” ref.current๋ฅผ ์“ฐ๊ฑฐ๋‚˜ ์ฝ์ง€ ๋งˆ์„ธ์š”.

React๋Š” ์ปดํฌ๋„ŒํŠธ์˜ ๋ณธ๋ฌธ์ด ์ˆœ์ˆ˜ ํ•จ์ˆ˜์ฒ˜๋Ÿผ ๋™์ž‘ํ•˜๊ธฐ๋ฅผ ๊ธฐ๋Œ€ํ•ฉ๋‹ˆ๋‹ค:

  • ์ž…๋ ฅ๊ฐ’๋“ค(props, state, context)์ด ๋™์ผํ•˜๋ฉด ์™„์ „ํžˆ ๋™์ผํ•œ JSX๋ฅผ ๋ฐ˜ํ™˜ํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค.
  • ๋‹ค๋ฅธ ์ˆœ์„œ๋‚˜ ๋‹ค๋ฅธ ์ธ์ˆ˜๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ํ˜ธ์ถœํ•ด๋„ ๋‹ค๋ฅธ ํ˜ธ์ถœ์˜ ๊ฒฐ๊ณผ์— ์˜ํ–ฅ์„ ๋ฏธ์น˜์ง€ ์•Š์•„์•ผ ํ•ฉ๋‹ˆ๋‹ค.

๋ Œ๋”๋ง ์ค‘์— ref๋ฅผ ์ฝ๊ฑฐ๋‚˜ ์“ฐ๋ฉด ์ด๋Ÿฌํ•œ ๊ธฐ๋Œ€๊ฐ€ ๊นจ์ง‘๋‹ˆ๋‹ค.

function MyComponent() {
// ...
// ๐Ÿšฉ Don't write a ref during rendering
myRef.current = 123;
// ...
// ๐Ÿšฉ Don't read a ref during rendering
return <h1>{myOtherRef.current}</h1>;
}

๋Œ€์‹  ์ด๋ฒคํŠธ ํ•ธ๋“ค๋Ÿฌ๋‚˜ Effect์—์„œ ref๋ฅผ ์ฝ๊ฑฐ๋‚˜ ์“ธ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

function MyComponent() {
// ...
useEffect(() => {
// โœ… You can read or write refs in effects
myRef.current = 123;
});
// ...
function handleClick() {
// โœ… You can read or write refs in event handlers
doSomething(myOtherRef.current);
}
// ...
}

๋ Œ๋”๋ง ์ค‘์— ๋ฌด์–ธ๊ฐ€๋ฅผ ์ฝ๊ฑฐ๋‚˜ ์จ์•ผ๋งŒ ํ•˜๋Š” ๊ฒฝ์šฐ, ๋Œ€์‹  state๋ฅผ ์‚ฌ์šฉํ•˜์„ธ์š”.

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


ref๋กœ DOM ์กฐ์ž‘ํ•˜๊ธฐ

ref๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ DOM์„ ์กฐ์ž‘ํ•˜๋Š” ๊ฒƒ์€ ํŠนํžˆ ์ผ๋ฐ˜์ ์ž…๋‹ˆ๋‹ค. React์—๋Š” ์ด๋ฅผ ์œ„ํ•œ ๊ธฐ๋ณธ ์ง€์›์ด ์žˆ์Šต๋‹ˆ๋‹ค.

๋จผ์ € ์ดˆ๊ธฐ๊ฐ’์ด null์ธ ref ๊ฐ์ฒด๋ฅผ ์„ ์–ธํ•˜์„ธ์š”:

import { useRef } from 'react';

function MyComponent() {
const inputRef = useRef(null);
// ...

๊ทธ๋Ÿฐ ๋‹ค์Œ ref ๊ฐ์ฒด๋ฅผ ref ์†์„ฑ์œผ๋กœ ์กฐ์ž‘ํ•˜๋ ค๋Š” DOM ๋…ธ๋“œ์˜ JSX์— ์ „๋‹ฌํ•˜์„ธ์š”:

// ...
return <input ref={inputRef} />;

React๊ฐ€ DOM ๋…ธ๋“œ๋ฅผ ์ƒ์„ฑํ•˜๊ณ  ํ™”๋ฉด์— ๊ทธ๋ฆฐ ํ›„, React๋Š” ref ๊ฐ์ฒด์˜ currentํ”„๋กœํผํ‹ฐ๋ฅผ DOM ๋…ธ๋“œ๋กœ ์„ค์ •ํ•ฉ๋‹ˆ๋‹ค. ์ด์ œ DOM ๋…ธ๋“œ <input> ์ ‘๊ทผํ•ด focus()์™€ ๊ฐ™์€ ๋ฉ”์„œ๋“œ๋ฅผ ํ˜ธ์ถœํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

function handleClick() {
inputRef.current.focus();
}

๋…ธ๋“œ๊ฐ€ ํ™”๋ฉด์—์„œ ์ œ๊ฑฐ๋˜๋ฉด React๋Š” current ํ”„๋กœํผํ‹ฐ๋ฅผ ๋‹ค์‹œ null๋กœ ์„ค์ •ํ•ฉ๋‹ˆ๋‹ค.

์ž์„ธํ•œ ๋‚ด์šฉ์€ ref๋กœ DOM ์กฐ์ž‘ํ•˜๊ธฐ์—์„œ ์•Œ์•„๋ณด์„ธ์š”.

useRef๋กœ DOM์„ ์กฐ์ž‘ํ•˜๋Š” ์˜ˆ์‹œ

์˜ˆ์ œ 1 of 4:
ํ…์ŠคํŠธ input์— ์ดˆ์  ๋งž์ถ”๊ธฐ

์ด ์˜ˆ์ œ์—์„œ๋Š” ๋ฒ„ํŠผ์„ ํด๋ฆญํ•˜๋ฉด ์ž…๋ ฅ์— ์ดˆ์ ์ด ๋งž์ถฐ์ง‘๋‹ˆ๋‹ค:

import { useRef } from 'react';

export default function Form() {
  const inputRef = useRef(null);

  function handleClick() {
    inputRef.current.focus();
  }

  return (
    <>
      <input ref={inputRef} />
      <button onClick={handleClick}>
        Focus the input
      </button>
    </>
  );
}


ref ์ฝ˜ํ…์ธ  ์žฌ์ƒ์„ฑ ํ”ผํ•˜๊ธฐ

React๋Š” ์ดˆ๊ธฐ์— ref ๊ฐ’์„ ํ•œ ๋ฒˆ ์ €์žฅํ•˜๊ณ , ๋‹ค์Œ ๋ Œ๋”๋ง๋ถ€ํ„ฐ๋Š” ์ด๋ฅผ ๋ฌด์‹œํ•ฉ๋‹ˆ๋‹ค.

function Video() {
const playerRef = useRef(new VideoPlayer());
// ...

new VideoPlayer()์˜ ๊ฒฐ๊ณผ๋Š” ์ดˆ๊ธฐ ๋ Œ๋”๋ง์—๋งŒ ์‚ฌ์šฉ๋˜์ง€๋งŒ, ํ˜ธ์ถœ ์ž์ฒด๋Š” ์ดํ›„์˜ ๋ชจ๋“  ๋ Œ๋”๋ง์—์„œ๋„ ์—ฌ์ „ํžˆ ๊ณ„์† ์ด๋ค„์ง‘๋‹ˆ๋‹ค. ์ด๋Š” ๊ฐ’๋น„์‹ผ ๊ฐ์ฒด๋ฅผ ์ƒ์„ฑํ•˜๋Š” ๊ฒฝ์šฐ ๋‚ญ๋น„์ผ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

์ด ๋ฌธ์ œ๋ฅผ ํ•ด๊ฒฐํ•˜๋ ค๋ฉด ๋Œ€์‹  ๋‹ค์Œ๊ณผ ๊ฐ™์ด ref๋ฅผ ์ดˆ๊ธฐํ™”ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค:

function Video() {
const playerRef = useRef(null);
if (playerRef.current === null) {
playerRef.current = new VideoPlayer();
}
// ...

์ผ๋ฐ˜์ ์œผ๋กœ ๋ Œ๋”๋ง ์ค‘์— ref.current๋ฅผ ์“ฐ๊ฑฐ๋‚˜ ์ฝ๋Š” ๊ฒƒ์€ ํ—ˆ์šฉ๋˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค. ํ•˜์ง€๋งŒ ์ด ๊ฒฝ์šฐ์—๋Š” ๊ฒฐ๊ณผ๊ฐ€ ํ•ญ์ƒ ๋™์ผํ•˜๊ณ  ์ดˆ๊ธฐํ™” ์ค‘์—๋งŒ ์กฐ๊ฑด์ด ์‹คํ–‰๋˜๋ฏ€๋กœ ์ถฉ๋ถ„ํžˆ ์˜ˆ์ธกํ•  ์ˆ˜ ์žˆ์œผ๋ฏ€๋กœ ๊ดœ์ฐฎ์Šต๋‹ˆ๋‹ค.

Deep Dive

useRef๋ฅผ ์ดˆ๊ธฐํ™”ํ•  ๋•Œ null ๊ฒ€์‚ฌ๋ฅผ ํ”ผํ•˜๋Š” ๋ฐฉ๋ฒ•

ํƒ€์ž… ๊ฒ€์‚ฌ๊ธฐ๋ฅผ ์‚ฌ์šฉํ•˜๋ฉด์„œ ํ•ญ์ƒ null์„ ๊ฒ€์‚ฌํ•˜๊ณ  ์‹ถ์ง€ ์•Š๋‹ค๋ฉด ๋‹ค์Œ๊ณผ ๊ฐ™์€ ํŒจํ„ด์„ ๋Œ€์‹  ์‚ฌ์šฉํ•ด ๋ณผ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค:

function Video() {
const playerRef = useRef(null);

function getPlayer() {
if (playerRef.current !== null) {
return playerRef.current;
}
const player = new VideoPlayer();
playerRef.current = player;
return player;
}

// ...

์—ฌ๊ธฐ์„œ playerRef ์ž์ฒด๋Š” nullableํ•ฉ๋‹ˆ๋‹ค. ํ•˜์ง€๋งŒ ํƒ€์ž… ๊ฒ€์‚ฌ๊ธฐ์— getPlayer()๊ฐ€ null์„ ๋ฐ˜ํ™˜ํ•˜๋Š” ๊ฒฝ์šฐ๊ฐ€ ์—†๋‹ค๋Š” ๊ฒƒ์„ ํ™•์‹ ์‹œํ‚ฌ ์ˆ˜ ์žˆ์–ด์•ผ ํ•ฉ๋‹ˆ๋‹ค. ๊ทธ๋Ÿฐ ๋‹ค์Œ ์ด๋ฒคํŠธ ํ•ธ๋“ค๋Ÿฌ์—์„œ getPlayer()๋ฅผ ์‚ฌ์šฉํ•˜์‹ญ์‹œ์˜ค.


๋ฌธ์ œ ํ•ด๊ฒฐ

์ปค์Šคํ…€ ์ปดํฌ๋„ŒํŠธ์— ๋Œ€ํ•œ ref๋ฅผ ์–ป์„ ์ˆ˜ ์—†์Šต๋‹ˆ๋‹ค

์ปดํฌ๋„ŒํŠธ์— ref๋ฅผ ์ „๋‹ฌํ•˜๊ณ ์ž ๋‹ค์Œ๊ณผ ๊ฐ™์ด ํ•˜๋ฉด:

const inputRef = useRef(null);

return <MyInput ref={inputRef} />;

๋‹ค์Œ๊ณผ ๊ฐ™์€ ์˜ค๋ฅ˜๊ฐ€ ๋ฐœ์ƒํ•  ๊ฒƒ์ž…๋‹ˆ๋‹ค:

Console
๊ฒฝ๊ณ : ํ•จ์ˆ˜ ์ปดํฌ๋„ŒํŠธ์—๋Š” ref๋ฅผ ์ง€์ •ํ•  ์ˆ˜ ์—†์Šต๋‹ˆ๋‹ค. ์ด ref์— ์ ‘๊ทผํ•˜๋ ค๋Š” ์‹œ๋„๋Š” ์‹คํŒจํ•ฉ๋‹ˆ๋‹ค. React.forwardRef()๋ฅผ ์‚ฌ์šฉํ•˜๋ ค๊ณ  ํ•˜์…จ๋‚˜์š”?

๊ธฐ๋ณธ์ ์œผ๋กœ ์ปดํฌ๋„ŒํŠธ๋Š” ๋‚ด๋ถ€์˜ DOM ๋…ธ๋“œ์— ๋Œ€ํ•œ ref๋ฅผ ์™ธ๋ถ€๋กœ ๋…ธ์ถœํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค.

์ด ๋ฌธ์ œ๋ฅผ ํ•ด๊ฒฐํ•˜๋ ค๋ฉด ref๋ฅผ ๊ฐ€์ ธ์˜ค๊ณ ์ž ํ•˜๋Š” ์ปดํฌ๋„ŒํŠธ๋ฅผ ์ฐพ์œผ์„ธ์š”:

export default function MyInput({ value, onChange }) {
return (
<input
value={value}
onChange={onChange}
/>
);
}

๊ทธ๋Ÿฐ ๋‹ค์Œ ์•„๋ž˜์™€ ๊ฐ™์ด forwardRef๋กœ ๊ฐ์‹ธ์„ธ์š”:

import { forwardRef } from 'react';

const MyInput = forwardRef(({ value, onChange }, ref) => {
return (
<input
value={value}
onChange={onChange}
ref={ref}
/>
);
});

export default MyInput;

๊ทธ๋Ÿฌ๋ฉด ๋ถ€๋ชจ ์ปดํฌ๋„ŒํŠธ๊ฐ€ ref๋ฅผ ๊ฐ€์ ธ์˜ฌ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

์ž์„ธํ•œ ๋‚ด์šฉ์€ ๋‹ค๋ฅธ ์ปดํฌ๋„ŒํŠธ์˜ DOM ๋…ธ๋“œ์— ์ ‘๊ทผํ•˜๊ธฐ์—์„œ ํ™•์ธํ•˜์„ธ์š”.