본문 바로가기
🩵 React/학습 노트

[React🩵] useRef

by 솔비님 2025. 3. 14.

01.  useRef

useState와 더불어 특정 값을 저장하기 위해 사용하는 대표적인 React hook
리랜더링과 상관없이 값을 기억하기 위해 사용되며(렌더링과 상관없이 변수를 유지), 자바스크립트 DOM API를 직접 사용하지 않고 DOM 요소에 직접 접근할 때 사용된다

 

 

 

02.  사용 방법

import "./App.css";
import { useRef } from "react";

function App() {
  const ref = useRef("초기값");  //👈🏻초기 값
  console.log("ref 1", ref);

  ref.current = "바꾼 값";   //👈🏻변경 값
  console.log("ref 1", ref);

  return (
    <div>
      <p>useRef에 대한 이야기에요.</p>
    </div>
  );
}

export default App;

 

 

콘솔을 확인해 보면 아래와 같이 ref에 초기값과 바꾼값이 담겨있다

세번 출력되는 이유는 리액트의 Strict Mode(엄격모드) 때문이라고 한다

 


1️⃣  컴포넌트가 처음 렌더링되면서 실행됨

  • ref가 "초기값"으로 설정됨
    👉🏻  첫 번째 console.log("ref 1", ref); 실행 → { current: "초기값" } 출력
  • ref.current = "바꾼 값" 실행
    👉🏻  두 번째 console.log("ref 1", ref); 실행 → { current: "바꾼 값" } 출력

2️⃣  React Strict Mode로 인해 개발 모드에서 App이 한 번 더 렌더링됨

  • 위 과정이 다시 한 번 반복되면서 같은 값이 두 번 더 출력됨
  • 그래서 "바꾼 값"이 세 번 출력됨

 

💡 여기서 나오는 current란? 

useRef가 참조하고 있는 값(Reference)을 저장하는 속성
useRef를 선언하면 객체 형태로 {current: 값}이 만들어지고 내부의 current가 실제 값을 가르킴

 

 

 

03.  useState와의 차이점

Ref는 State와 비슷한 역할을 하지만,

  • useState는 변화가 일어나면 렌더링이 일어나고 내부 변수가 초기화 된다 👉🏻 리렌더링이 꼭 필요한 값에 사용한다
  • useRef는 저장한 값들은 랜더링이 일어나지 않는다 = Ref값의 변화가 생겨도 렌더링으로 인해 내부 변수가 초기화되는 것을 막을 수 있다.
    컴포넌트가 100번 렌더링 되더라도 Ref에 저장된 값은 유지된다 👉🏻 리렌더링을 발생시키지 않는 값을 저장할 때 사용한다

 

아래 예시 코드를 복사해서 실행해 보면 더 확실하게 차이를 알 수 있다

 

 

import "./App.css";
import { useRef, useState } from "react";

function App() {
  const [count, setCount] = useState(0);
  const countRef = useRef(0);

  const plusStateCountButtonHandler = () => {
    setCount(count + 1);
  };

  const plusRefCountButtonHandler = () => {
    countRef.current++;
  };

  return (
    <>
      <div>
        state 영역입니다. {count} <br />
        <button onClick={plusStateCountButtonHandler}>state 증가</button>
      </div>
      <div>
        ref 영역입니다. {countRef.current} <br />
        <button onClick={plusRefCountButtonHandler}>ref 증가</button>
      </div>
    </>
  );
}

export default App;

 

 

✔️ state가 변경되면 React는 컴포넌트를 다시 렌더링하며, 변경된 state 값을 반영하여 화면을 업데이트한다

✔️ 하지만 ref는 값이 변경되어도 컴포넌트가 다시 렌더링되지 않으며, 화면도 자동으로 업데이트되지 않는다

 

 

 

04.  DOM 요소에 접근해보기

아래와 같이 간단히 input 값을 입력받는 구조를 만들어 보았다

import "./App.css";

function App() {
  return (
    <>
      <div>
        아이디 : <input type="text" />
      </div>
      <div>
        비밀번호 : <input type="password" />
      </div>
    </>
  );
}

export default App;

 

코드 실행 화면

 

 

이때 화면이 렌더링 되고나면 input 범위에 마우스를 클릭해야 입력할 수 있다

하지만 useRef를 사용하면 자동으로 포커싱을 줄 수 있음

 

 

import { useEffect, useRef } from "react";
import "./App.css";

function App() {
  const idRef = useRef("");

  // 렌더링이 될 때
  useEffect(() => {
    idRef.current.focus();
  }, []);

  return (
    <>
      <div>
        아이디 : <input type="text" ref={idRef} />
      </div>
      <div>
        비밀번호 : <input type="password" />
      </div>
    </>
  );
}

export default App;

 

이 코드를 보면 input요소에 참조할 ref를 생성하고,

컴포넌트가 처음 렌더링된 후 실행할 수 있도록 useEffect로 받아서 focus를 주고있다

 

id에 자동으로 focus 되고있는 모습

 

 

왜 useEffect 안에서 focus()를 호출해야 할까?

 

 

idRef.current.focus(); // ❌ useEffect 없이 실행하면 에러 가능

 

위 코드처럼 useEffect 없이 실행하면 초기 렌더링 시 input요소가 아직 생성되지 않았기 때문에 null 오류가 발생할 수 있다

 

 

useEffect(() => {
  idRef.current.focus(); //컴포넌트가 렌더링된 후 실행됨
}, []);

 

useEffect 사용 시 첫 렌더링(마운트) 이후 한 번만 실행되므로 안전하게 focus()를 적용할 수 있다

(별다른 이벤트 감지 없이 첫 렌더링 시 자동으로 실행되는 코드를 담는 역할을 한다)