React – 상태 관리와 Hooks – 기본 Hooks – 2 – useRef로 DOM 제어 및 값 보존

React – 상태 관리와 Hooks – 기본 Hooks – 2 – useRef로 DOM 제어 및 값 보존

React – 상태 관리와 Hooks – 기본 Hooks – 2 – useRef로 DOM 제어 및 값 보존

안녕하세요! 😊
오늘은 React에서 아주 유용하게 사용되는 useRef에 대해 깊이 있게 알아보려 해요.
이 친구는 조금 낯설지만, 알고 보면 정말 똑똑하고 다양한 상황에서 활용할 수 있는 “비밀 무기” 같은 존재랍니다!

우리가 흔히 생각하는 “ref = DOM 제어용”이라는 인식도 맞지만, 그보다 훨~씬 많은 일을 할 수 있어요.
그럼 함께 차근차근 살펴볼까요?


1. useRef란 무엇인가요?

useRef는 말 그대로 “참조(ref)”를 의미합니다.
React에서 DOM 요소나 특정 값을 기억하고 참조하기 위한 객체를 만들 때 사용돼요.

const myRef = useRef(초기값);
  • myRef.current를 통해 실제 값을 읽거나 쓸 수 있습니다.
  • 이 값은 렌더링 사이에서도 유지됩니다!
  • 하지만 값이 바뀌어도 리렌더링이 발생하지 않아요!

2. DOM 요소에 접근할 때

가장 기본적인 용도는 HTML DOM에 직접 접근할 때예요.
예전 class 컴포넌트의 ref 속성을 함수형 컴포넌트에서도 사용 가능하게 해줍니다.

예제: 포커스 주기

import { useRef } from 'react';

function InputFocus() {
  const inputRef = useRef(null);

  const handleClick = () => {
    inputRef.current.focus(); // DOM 요소에 직접 접근
  };

  return (
    <div>
      <input ref={inputRef} type="text" placeholder="입력하세요" />
      <button onClick={handleClick}>포커스 주기</button>
    </div>
  );
}

🧠 비유하자면?

useRef는 마치 “리모컨” 같아요.
버튼 하나로 특정 요소를 직접 조작할 수 있죠!
CSS나 이벤트로 안 되는 직접적인 동작 제어에 아주 유용하답니다.


3. 값 보존용 useRef

useRef는 꼭 DOM 요소가 아니라, 리렌더링을 막으면서 어떤 값을 기억하고 싶을 때도 사용할 수 있어요.

예제: 이전 값 기억하기

import { useState, useEffect, useRef } from 'react';

function PreviousCounter() {
  const [count, setCount] = useState(0);
  const prevCountRef = useRef();

  useEffect(() => {
    prevCountRef.current = count;
  }, [count]);

  return (
    <div>
      <p>현재 값: {count}</p>
      <p>이전 값: {prevCountRef.current}</p>
      <button onClick={() => setCount(count + 1)}>+1</button>
    </div>
  );
}
  • prevCountRef.current는 렌더 사이클이 바뀌어도 유지되므로 값 추적에 매우 유용해요.
  • 일반 변수로는 안 되는 일이죠!

4. useRef vs useState 차이점

항목 useState useRef
렌더링 유발 값 변경 시 리렌더링 발생 ❌ 발생하지 않음
값 유지 ✅ 가능 ✅ 가능
DOM 접근 ❌ 불가능 ✅ 가능
비동기 값 저장 ⚠️ 제한 있음 ✅ 유용함

즉, 렌더링 없이 값을 저장하거나 DOM 직접 제어하고 싶을 때useRef가 훨씬 적합해요!


5. 실전 예제: 딜레이 버튼 연속 클릭 방지

function PreventDoubleClick() {
  const isClickedRef = useRef(false);

  const handleClick = () => {
    if (isClickedRef.current) {
      alert('잠시 기다려주세요!');
      return;
    }

    isClickedRef.current = true;
    alert('처리 중...');

    setTimeout(() => {
      isClickedRef.current = false;
    }, 2000);
  };

  return <button onClick={handleClick}>제출</button>;
}
  • 렌더링 없이 내부 상태를 기억하는 데 딱 좋아요!
  • useState로 하면 버튼 누를 때마다 렌더링이 발생할 거예요.

6. useRef의 자주 쓰이는 상황

상황 설명
input 등 DOM 제어 포커스, 선택, 스크롤 등 직접 조작
이전 값 기억 이전 상태와 비교
타이머/인터벌 ID 저장 clearTimeout 등을 위해 참조 필요
렌더링 없이 플래그 유지 비동기 요청 중 여부, 초기 렌더 여부 등
canvas, audio 등 직접 접근 DOM 객체 조작에 꼭 필요함

7. 의외로 중요한 사용법: setInterval과 함께 쓰기

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

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

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

  return <p>콘솔을 확인해보세요!</p>;
}
  • setInterval 내부는 클로저라서 기존 값만 기억해요.
  • useRef를 사용하면 항상 최신 값을 저장하고 접근할 수 있어요.

8. 자주 하는 실수와 주의사항

실수 설명 해결 방법
ref.current에 직접 값을 할당 안 함 ref = null 상태 유지 ref.current = 값 꼭 설정
useRefuseState처럼 사용 값 바뀌어도 화면이 안 바뀜 UI 갱신 필요하면 useState 사용
렌더링 관련 값 보존 리렌더링 의도인데 ref 사용 이럴 땐 useState 또는 useMemo 고려
이벤트 핸들러 안에서 ref.current 값 의존 초기값만 기억할 수 있음 최신값 유지하려면 useRef에 계속 할당

마무리하며

useRef는 초보자에게는 조금 낯설 수 있지만, 컴포넌트의 동작을 유연하게 제어하는 강력한 도구입니다.
특히 렌더링 없이 어떤 값이나 DOM을 제어하고 싶을 때, useRef를 적극적으로 활용해보세요!

✅ 핵심 정리

useRef

  • DOM 직접 접근,
  • 값 보존 (렌더링 없음),
  • 타이머, 이전 값, 상태 플래그 등 관리에 유용한 훅입니다!

앞으로 useRef와 함께 useEffect, useCallback 등을 조합하면 더 복잡하고 강력한 컴포넌트를 만들 수 있어요!
다음 시간에는 성능 최적화를 위한 훅들 (useMemo, useCallback) 도 소개해드릴게요.
함께 꾸준히 연습하면서 React 마스터에 한 걸음 더 다가가 봅시다! 🚀💪

답글 남기기