[React] 12. useRef

서회정's avatar
Feb 28, 2026
[React] 12. useRef

1. useRef란

💡
use Reference의 약자로 컴포넌트 내부에 새로운 레퍼런스 객체를 생성해준다
그리고 만들어진 레퍼런스 객체는 컴포넌트 내부의 변수로서 일반적인 값들을 저장할 수 있다
notion image
 

⚠️ useState와 차이점

 
useState와의 차이는 리렌더링을 유발하지 않는다는 점이다.
따라서 랜더링에 영향을 미치지 않고자 하는 변수를 생성할 때 사용된다.
 
notion image
 
또한 useRef를 사용하면 컴포넌트가 렌더링하는 특정 DOM 요소에 접근하고, 해당 요소를 조작할 수 있다.
 
notion image
 

2. 실습

 
기존에 만들어 두었던 Register.jsx 를 활용하여 실습해보자.
 
import { useState } from "react"; const Register = () => { const [input, setInput] = useState({ name: "", birth: "", country: "", bio: "", }); const onChange = (e) => { setInput({ ...input, [e.target.name]: e.target.value, }); console.log(e); }; return ( <div> <div> <input name="name" value={input.name} onChange={onChange} placeholder="이름" /> </div> <div> <input name="birth" value={input.birth} onChange={onChange} type="date" /> </div> <div> <select name="country" value={input.country} onChange={onChange}> <option></option> <option value="kr">한국</option> <option value="us">미국</option> <option value="uk">영국</option> </select> </div> <div> <textarea name="bio" value={input.bio} onChange={onChange} /> </div> </div> ); }; export default Register;
 

1. useRef 불러오기

import { useState, useRef } from "react";
 

2. useRef 객체 생성 및 확인

 
먼저, useRef 객체를 생성해보자.
그리고 해당하는 객체 반환값을 알아보기 위해
콘솔에 출력해보자.
 
const refObj = useRef(); console.log(refObj);
 
만들어둔 useRef 객체의 구조를 확인해보면 다음과 같다.
current라는 프로퍼티만을 가지고 있으며,
 
해당하는 프로퍼티에 값을 담아두기만 하는
아주 간단한 자바스크립트 객체 형태이다.
 
notion image
 
해당 객체에는 초기값을 설정할 수 있는데,
랜더링에 영향을 주지 않기 때문에 초기값이
변경되어도 리랜더링이 되지 않는다.
 
const refObj = useRef(0); console.log("레지스터 랜더링");
 
<button onClick={() => { refObj.current++; console.log(refObj.current); } } > ref + 1 </button>
 
버튼을 클릭해도 리랜더링이 발생하지 않기 때문에
작성해 두었던 레지스터 랜더링이라는 문자는 한 번만 출력된다.
 
notion image
 

3. 여러 사례 적용해보기

1. 리랜더링 되지 않는 카운트 기능 만들기

 
다음으로는 레지스터 컴퍼넌트에서 사용자의 동작에 의해
얼마나 많은 횟수의 변경을 했는지 카운트할 수 있는 기능을 만들어보자.
 
우선 레퍼런스 객체를 생성할 때 만들었던 이름을 더 직관적으로 수정해주자.
 
const countRef = useRef(0);
 
그 다음, 이벤트 핸들러에 변경이 일어날 때마다
카운트 값이 1씩 증가할 수 있도록 증감식을 넣어주자.
 
const onChange = (e) => { countRef.current++; console.log(countRef.current); setInput({ ...input, [e.target.name]: e.target.value, }); };
 
사용자가 폼에 작성을 할 때마다 리랜더링되며
콘솔에 변경된 카운트가 찍히게 된다.
 
notion image
 

1. DOM 요소 직접 제어하기

 
이번에는 회원가입 폼을 제출하는 기능을 만들어보자.
 
먼저, 제출하는 기능을 만들기 위해 사용자가 제출을
할 수 있도록 버튼을 만들어주자.
 
폼의 가장 아래에 위치할 수 있도록 하자.
그리고 onClick 이벤트로 onSubmit을 기입해주자.
 
<button onClick={onSubmit}>제출</button>
 
그리고 실제 onSubmit 이벤트 핸들러를 만들자.
우선, onSubmit 이벤트에는 이름을 입력했는지 확인하는
조건문을 작성하고자한다.
 
사용자가 아무것도 입력하지 않으면 이름을 입력하는
DOM 요소가 포커스 되도록 해보자.
 
const onSubmit = (e) => { // 이름을 정확히 입력했는 지 확인 if (input.name === "") { // 이름을 입력하는 DOM 포커스 } };
 
이러한 기능을 만들기 위해서는 이름을 입력하는
폼의 DOM 요소를 가져와야한다.
 
그래서 래퍼런스 객체를 활용하여 input
DOM 요소를 저장하도록 해야한다.
 
먼저 inputRef라는 래퍼런스 객체를 만들자.
 
const inputRef = useRef();
 
다음으로 이를 저장할 input태그에 ref 속성으로
inputRef를 넣어 래퍼런스 객체의 current 프로퍼티에
저장할 수 있도록 하자.
 
<div> <input ref={inputRef} name="name" value={input.name} onChange={onChange} placeholder="이름" /> </div>;
 
inputRef에 값이 잘 저장되었는지 확인하기 위해
제출 버튼을 눌렀을 때 발생하는 이벤트 내에
콘솔 출력 기능을 넣어보자.
 
이름을 기입하지 않고 제출 버튼을 클릭했을 때
다음과 같이 콘솔에 해당 input의 DOM 요소가 잘
저장되어 출력되는 것을 확인할 수 있다.
 
notion image
 
그럼 이제, 콘솔은 삭제하고 DOM 요소의 메서드인 focus()를 호출 하기만 하면 된다.
 
const onSubmit = (e) => { // 이름을 정확히 입력했는 지 확인 if (input.name === "") { // 이름을 입력하는 DOM 포커스 inputRef.current.focus(); } };
 
notion image
 

3. useRef를 사용하는 이유?

 
useRef를 사용하는 목적은 리랜더링을 유발하지 않는
변수를 만들고자 하는데 있다.
 
그렇다면 자바스크립트 변수를 사용해도 되지 않을까?
하는 의문이 생길 수 있다.
 
그러나 이는 자바스크립트 변수를 사용해보면
useRef가 필요한지 알 수 있다.
 
아까 만들어두었던 예제를 활용해보자.
 

 
래퍼런스 객체가 아닌 자바스크립트 변수인 count
사용하면 화면을 실행했을 때 콘솔에 다음과 같은
결과를 확인할 수 있다.
 
let count = 0; const onChange = (e) => { count++; console.log(count); setInput({ ...input, [e.target.name]: e.target.value, }); };
 
증감식을 사용해도 count 값이 1로만 출력되는데
원인을 생각해보면 이유는 간단하다.
 
사용자의 입력에 따라 화면이 리랜더링 되는데 이는
해당 코드를 감싸고있는 레지스터 컴퍼넌트가 다시
호출되는 것이 원인이며,
 
이는 해당하는 컴퍼넌트 내에 있는 코드가 계속
리셋되는 것을 의미한다.
 
useRefuseState같은 경우에는 리랜더링 되어도
내부적으로 값이 리셋되지 않도록 설계되어 있기 때문에
자바스크립트 변수가 아닌 해당하는 기능을 사용해야하는 것이다.
 
notion image
 

✅ 컴퍼넌트 바깥에서 자바스크립트변수를 사용한다면?

 
그렇다면 레지스터 컴퍼넌트가 재호출되며 발생하는 리셋을
막기 위해 컴퍼넌트 바깥에서 자바스크립트 변수를 선언하면
해결되지 않을까?
 
라는 생각도 할 수 있다.
 
하지만 이는 프로젝트 전체를 망가트리는 더 심각한 문제를
유발할 수 있다.
 
만들어 둔 예제에서 확인해보자.
 

 
count라는 자바스크립트 변수를 컴퍼넌트 바깥에 두었을 때,
카운트가 증가되는 데에는 문제가 없어 보인다.
 
notion image
 
notion image
 
하지만 프로젝트가 커질 때 해당하는 컴퍼넌트가
여러 번 사용된다면 이야기는 달라진다.
 
레지스터를 감싸는 App.jsx에서 레지스터 컴퍼넌트를 두 번 호출하면
카운트 변수가 공유되어 사용되는 것을 확인할 수 있는데 원인은
간단하게 설명할 수 있다.
 
notion image
notion image
 
해당하는 컴퍼넌트가 있는 파일이 두 번 실행된 것이 아니라,
레지스터 함수와 카운트 변수는 한 번만 선언된 것이다.
 
따라서 함수가 두 번 호출 되기만 한 것이라 두 개의
컴퍼넌트가 마치 하나의 변수를 나눠 쓰고 있는 것처럼
동작하는 것이다.
 
따라서 컴퍼넌트에 각각 값을 관리하고자 한다면 컴퍼넌트
외부가 아닌 내부에서 선언하고 관리해야 하는 것이다.
 
그래서 특별한 경우가 아니라면 useRef를 사용하여 변수를 관리하자.
 
Share article

clubnerdy