[TIL/React] useRef 기본


What is useRef?

useRef는 렌더링에 필요하지 않은 값을 참조할 수 있는 React Hook입니다.

  • react 공식문서

말그대로 렌더링에 사용하지 않는 값을 참조하는 훅이며, 또는 DOM을 조작하기 위해서 주로 사용한다. 이 글에서는 가장 기본적인 사용법인 렌더링하지 않는 데이터 저장에 대해 알아본다.

컴포넌트가 일부 데이터를 기억하길 바라지만, state처럼 렌더링을 유발하지 않도록 하려면 ref를 사용한다.

사용법

기본적인 사용법은 다음과 같다.

// 1. react로부터 useRef를 가져온다
import { useRef } from 'react';

// 2. state처럼 초깃값을 함수에 파라미터로 전달한다.
const ref = useRef(0);

useRef는 다음처럼 객체를 반환한다.

{
    current: 0 // 초기화 값
}
  • ref.current를 통해서 해당 ref의 current 값에 접근할 수 있다.

  • 숫자, 문자열, 함수 등 모든 것을 가리킬 수 있다. (객체에 저장하는 거임)

state의 경우, 해당 값이 변경되면 렌더링이 발생하지만, ref의 경우, 값이 변경되어도 UI 렌더링이 발생하지는 않는다. state와 결합하여 사용되기도 하며 다음은 가장 대표적인 예시 중 하나인 countdown 예시이다.

import { useState, useRef } from 'react';

export default function Stopwatch() {
  const [startTime, setStartTime] = useState(null);
  const [now, setNow] = useState(null);
  // 타이머 구현을 위해 interval을 생성하는데, setInterval 함수를 ref로 저장해준다.
  // clearInterval을 통해 타이머를 멈추기 위해서 ref에 저장을 한 예시임
  const intervalRef = useRef(null);

  function handleStart() {
    setStartTime(Date.now());
    setNow(Date.now());

    // 타이머가 시작되면 intervalRef의 current 값에 setInterval()함수를 저장한다.
    clearInterval(intervalRef.current);
    intervalRef.current = setInterval(() => {
      setNow(Date.now());
    }, 10);
  }

  function handleStop() {
   // 종료 이벤트가 발생하면, intervalRef에 저장되어있던 interval을 종료할 수 있다.
    clearInterval(intervalRef.current);
  }

  let secondsPassed = 0;
  if (startTime != null && now != null) {
    secondsPassed = (now - startTime) / 1000;
  }

  return (
    <>
      <h1>Time passed: {secondsPassed.toFixed(3)}</h1>
      <button onClick={handleStart}>
        Start
      </button>
      <button onClick={handleStop}>
        Stop
      </button>
    </>
  );
}

useRef의 내부 동작

공식 문서에서는 useRef를 useState로 구현한 예시를 보여준다.

function useRef(initialValue) {
    // setter 함수를 사용하지 않고 ref라는 state에 저장된 객체만 뱉는다.
    const [ref, ununsed] = useState({ current: initialValue })
    return ref;
}

정리

  • Refs는 렌더링이 필요하지 않은 데이터 저장을 위해 사용

  • ref는 current라는 프로퍼티에 값을 저장하는 객체임

  • 컴포넌트 렌더링 간에 데이터를 유지할 수 있음 (렌더링 발생해도 값이 초기화되지 않는다.)

  • ref의 current 값을 변경해도 리렌더링이 발생하지 않는다.