[React] useRef와 forwardRef, useImperativeHandle 이해하기

Sara Jo·2025년 6월 11일
post-thumbnail

🤓: "useRef란 무엇인가요?"
👀: "React에서 DOM 요소에 직접 접근할 때 쓰는 hook입니다."

라고 면접 질문 답변식으로만 useRef를 이해하고 있었던 나..

실제로 업무할때도 기존의 코드를 참고해서 비슷한 방식으로 코드를 짜다보니 제대로 그 개념에 대해 이해하고 있지 못한채 사용하고 있는 것 같아 useRef, 그리고 그와 함께 자주 사용되는 forwardRef, useImperativeHandle에 대해 공부해보았다.


🔍 useRef란?

useRef는 React에서 제공하는 훅(Hook) 중 하나이다. 말 그대로 reference를 만들 때 사용하는데, 주로 다음과 같은 상황에서 쓰인다:

1. DOM 요소에 직접 접근할 때
2. 렌더링과 관계없는 값을 저장할 때 (리렌더링을 발생시키지 않음)

🧪 기본 사용법

import { useRef, useEffect } from 'react';

function MyComponent() {
  const inputRef = useRef<HTMLInputElement>(null);

  useEffect(() => {
    if (inputRef.current) {
      inputRef.current.focus(); // 컴포넌트 마운트 시 자동 포커싱
    }
  }, []);

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

💡 렌더링과 관계없는 값 저장하기

function Timer() {
  const count = useRef(0);

  useEffect(() => {
    const interval = setInterval(() => {
      count.current += 1;
      console.log('현재 카운트:', count.current);
    }, 1000);

    return () => clearInterval(interval);
  }, []);

  return <div>콘솔을 확인해보자!</div>;
}

이 예제처럼 useRef는 값이 바뀌어도 리렌더링되지 않는다. 그래서 단순히 값을 저장하거나 유지하는 용도로도 자주 사용된다.


🚪 forwardRef란?

forwardRef부모 컴포넌트가 자식 컴포넌트의 DOM 요소나 내부 인스턴스에 ref를 전달할 수 있도록 해주는 React의 기능이다.

기본적으로 ref는 HTML 요소에만 바로 전달되지만, 커스텀 컴포넌트에는 기본적으로 전달되지 않는다. 그걸 해결해주는 게 forwardRef이다.

🔧 기본 사용법

import { forwardRef } from 'react';

const MyInput = forwardRef<HTMLInputElement, React.ComponentProps<'input'>>((props, ref) => {
  return <input {...props} ref={ref} />;
});

이제 이 MyInput 컴포넌트는 외부에서 ref를 받아서 내부의 input에 전달해줄 수 있게 된다.

function Parent() {
  const inputRef = useRef<HTMLInputElement>(null);

  const focusInput = () => {
    inputRef.current?.focus();
  };

  return (
    <>
      <MyInput ref={inputRef} />
      <button onClick={focusInput}>포커스 주기</button>
    </>
  );
}

🤔 forwardRef는 어디서 써야 하는거지?

여기서 조금 헷갈린 부분이 있다.
"ref는 어디서 쓰는거고 forwardRef는 또 어디서 쓰는거지?"

forwardRef는 자식 컴포넌트를 선언할 때 사용하고, ref는 부모 컴포넌트에서 사용한다.

✅ 정리하자면

역할사용하는 위치
forwardRef자식 컴포넌트를 선언할 때 사용
ref부모 컴포넌트에서 사용

즉, forwardRef자식이 외부에서 ref를 받을 준비를 하는 거고,
부모는 그냥 ref를 달아주기만 하면 되는 구조
다.


🧙‍♂️ useImperativeHandle과 같이 쓰기

가끔은 ref를 단순히 DOM 요소에만 전달하는 게 아니라, 컴포넌트 외부에서 내부 메서드를 사용할 수 있도록 하고 싶을 때도 있다.
그럴 땐 useImperativeHandle과 같이 사용하면 된다.

import { forwardRef, useImperativeHandle, useRef } from 'react';

const FancyInput = forwardRef((_, ref) => {
  const inputRef = useRef<HTMLInputElement>(null);

  useImperativeHandle(ref, () => ({
    focus: () => {
      inputRef.current?.focus();
    },
    clear: () => {
      if (inputRef.current) {
        inputRef.current.value = '';
      }
    },
  }));

  return <input ref={inputRef} />;
});
function Parent() {
  const fancyRef = useRef<{ focus: () => void; clear: () => void }>(null);

  return (
    <>
      <FancyInput ref={fancyRef} />
      <button onClick={() => fancyRef.current?.focus()}>포커스</button>
      <button onClick={() => fancyRef.current?.clear()}>클리어</button>
    </>
  );
}

이렇게 하면 외부에서 컴포넌트 내부의 특정 동작을 제어할 수 있다.


✅ 마무리

useRefforwardRef는 특히 사용자 정의 input이나 modal, focus 컨트롤이 필요한 UI에서 자주 쓰이니 잘 익혀두었다가 유용하게 사용하자!

0개의 댓글