
React의 useRef는 컴포넌트의 상태 관리와 DOM 접근을 간단하고 효율적으로 처리할 수 있는 강력한 도구입니다. 이번 포스트에서는 useRef의 기본 개념, 사용 방법, 그리고 활용 사례를 중심으로 설명합니다. 특히, 렌더링 최적화와 상태 관리의 차이점을 이해하고, 실무에서 useRef를 어떻게 활용할 수 있는지 알아보겠습니다.
1. useRef
란 무엇인가?
useRef는 React에서 제공하는 Hook 중 하나로, **참조(ref)**를 생성하고 관리하기 위해 사용됩니다. 주로 DOM 요소에 직접 접근하거나, 컴포넌트의 상태와는 독립적으로 값을 저장하고 유지할 때 활용됩니다.
useRef
는 React의 상태 관리와는 다르게, 값이 변경되어도 컴포넌트를 다시 렌더링하지 않는 특징이 있습니다. 따라서 렌더링과 관계없이 값을 유지하거나 DOM 요소를 조작해야 할 때 유용합니다.
주요 특징
- 렌더링을 발생시키지 않음:
useRef
로 관리하는 값은 변경되어도 컴포넌트를 다시 렌더링하지 않습니다. - 컴포넌트 생애주기 동안 값 유지:
useRef
로 저장된 값은 컴포넌트가 언마운트될 때까지 유지됩니다. - DOM 요소 접근: 특정 DOM 요소에 직접 접근하여 조작할 수 있습니다.
2. useRef
의 기본 사용법
useRef
는 React에서 상태 관리와 DOM 접근을 간단히 처리할 수 있습니다. 기본적인 사용법은 다음과 같습니다:
상태 관리에 useRef
사용하기
import React, { useRef } from "react";
function Counter() {
const countRef = useRef(0); // 초기값 설정
const increment = () => {
countRef.current += 1; // current를 통해 값에 접근
console.log("Current count:", countRef.current);
};
return (
<div>
<button onClick={increment}>Increment</button>
<p>Check the console for the count value!</p>
</div>
);
}
export default Counter;
DOM 접근에 useRef
사용하기
import React, { useRef } from "react";
function InputFocus() {
const inputRef = useRef(null);
const focusInput = () => {
inputRef.current.focus(); // input 요소에 포커스
};
return (
<div>
<input ref={inputRef} type="text" placeholder="Type something..." />
<button onClick={focusInput}>Focus Input</button>
</div>
);
}
export default InputFocus;
3. useRef
와 useState
의 차이점
useRef
와 useState
는 모두 값을 저장할 수 있지만, 다음과 같은 차이점이 있습니다:
특징 | useRef | useState |
렌더링 발생 여부 | 값이 변경되어도 렌더링을 발생시키지 않음 | 값이 변경되면 컴포넌트를 다시 렌더링 |
주요 사용 목적 | DOM 접근, 렌더링과 무관한 값 저장 | UI 업데이트를 위한 상태 관리 |
값 유지 기간 | 컴포넌트 생애주기 동안 유지 | 상태가 변경될 때마다 새로운 값으로 업데이트 |
4. useRef를 사용하는 주요 사례
4.1. DOM 요소 접근 및 조작
useRef
는 DOM 요소에 직접 접근해야 할 때 유용합니다. 예를 들어, 특정 입력 필드에 포커스를 주거나 스크롤 위치를 제어할 때 사용할 수 있습니다.
function ScrollToTop() {
const divRef = useRef(null);
const scrollToTop = () => {
divRef.current.scrollTop = 0; // 스크롤 위치를 맨 위로 이동
};
return (
<div>
<div ref={divRef} style={{ height: "200px", overflow: "auto" }}>
<p>긴 내용...</p>
</div>
<button onClick={scrollToTop}>Scroll to Top</button>
</div>
);
}
4.2. 렌더링 횟수 추적
컴포넌트가 몇 번 렌더링되었는지 추적할 때 useRef
를 사용할 수 있습니다.
function RenderCounter() {
const renderCount = useRef(1);
useEffect(() => {
renderCount.current += 1;
console.log("Render Count:", renderCount.current);
});
return <p>Check the console for render count!</p>;
}
4.3. 이전 값 저장
useRef
를 사용하여 이전 상태 값을 저장할 수 있습니다.
function PreviousValue() {
const [count, setCount] = useState(0);
const prevCount = useRef(0);
useEffect(() => {
prevCount.current = count; // 현재 값을 이전 값으로 저장
}, [count]);
return (
<div>
<p>Current Count: {count}</p>
<p>Previous Count: {prevCount.current}</p>
<button onClick={() => setCount(count + 1)}>Increment</button>
</div>
);
}
4.4. 성능 최적화
useRef
는 렌더링과 무관한 값을 저장할 때 유용합니다. 예를 들어, 애니메이션 프레임 ID나 타이머 ID를 저장하여 불필요한 렌더링을 방지할 수 있습니다.
function Timer() {
const timerId = useRef(null);
const startTimer = () => {
timerId.current = setInterval(() => {
console.log("Timer running...");
}, 1000);
};
const stopTimer = () => {
clearInterval(timerId.current);
};
return (
<div>
<button onClick={startTimer}>Start Timer</button>
<button onClick={stopTimer}>Stop Timer</button>
</div>
);
}
4.5. 외부 라이브러리와의 통합
useRef
는 외부 라이브러리와 React를 통합할 때도 자주 사용됩니다. 예를 들어, 차트 라이브러리나 캔버스 API와 같은 DOM 기반 라이브러리를 사용할 때 useRef
를 통해 DOM 요소를 참조할 수 있습니다.
import { useEffect, useRef } from "react";
function CanvasExample() {
const canvasRef = useRef(null);
useEffect(() => {
const canvas = canvasRef.current;
const ctx = canvas.getContext("2d");
ctx.fillStyle = "blue";
ctx.fillRect(0, 0, 100, 100);
}, []);
return <canvas ref={canvasRef} width={200} height={200}></canvas>;
}
5. useRef
의 장점과 주의점
장점
- DOM 요소에 직접 접근 가능
useRef
를 사용하면 React의 선언적 방식과 함께 특정 DOM 요소에 직접 접근할 수 있습니다. 예를 들어, 포커스 설정, 스크롤 위치 조정, 또는 Canvas와 같은 DOM 요소를 조작할 때 유용합니다. - 렌더링 없이 값 유지
useRef
는 컴포넌트가 다시 렌더링되더라도 값이 초기화되지 않고 유지됩니다. 상태(useState
)와는 다르게 값이 변경되어도 컴포넌트를 다시 렌더링하지 않으므로, 불필요한 렌더링을 방지할 수 있습니다. - 타이머, 이벤트 핸들러 등 외부 값 관리
useRef
는 타이머 ID, 이전 상태 값, 또는 이벤트 핸들러와 같은 값을 저장하고 관리하는 데 적합합니다. 이를 통해 상태와는 독립적으로 외부 값을 안전하게 관리할 수 있습니다. - 초기화 비용 절감
useRef
는 초기화 시점에만 값을 설정하며, 이후에는 값이 유지되므로 초기화 비용이 높은 작업을 반복적으로 수행하지 않아도 됩니다. - React의 상태 관리와 분리
useRef
는 React의 상태 관리와 별개로 동작하므로, 상태를 변경하지 않고도 값을 저장하거나 참조할 수 있습니다. 이는 상태 변경으로 인해 발생하는 불필요한 렌더링을 방지하는 데 유용합니다.
주의점
- 값 변경 시 렌더링되지 않음
useRef
의 값이 변경되어도 컴포넌트는 다시 렌더링되지 않습니다. 따라서, 값 변경에 따라 UI를 업데이트해야 하는 경우에는useState
를 사용해야 합니다 - DOM 조작은 최소화해야 함
React는 선언적 UI를 지향하므로,useRef
를 사용한 DOM 조작은 꼭 필요한 경우에만 사용해야 합니다. 과도한 DOM 조작은 React의 상태 관리와 충돌하거나, 코드의 유지보수성을 떨어뜨릴 수 있습니다. - 초기값 설정 주의
useRef
는 초기값을 설정하지 않으면undefined
를 반환합니다. 따라서, 초기값이 필요한 경우 명시적으로 설정해야 합니다. - 클린업 처리 필요
useRef
를 사용해 타이머나 이벤트 핸들러를 관리할 경우, 컴포넌트가 언마운트될 때 이를 정리하지 않으면 메모리 누수나 예기치 않은 동작이 발생할 수 있습니다. - React의 상태 관리와 혼동 주의
useRef
는 상태 관리가 아닌 참조를 위한 도구입니다. 상태 변경과 관련된 작업에는 반드시useState
를 사용해야 하며,useRef
를 잘못 사용하면 React의 상태 관리 흐름을 방해할 수 있습니다.
6. 결론
useRef
는 React에서 상태 관리와 DOM 접근을 효율적으로 처리할 수 있는 강력한 도구입니다. 렌더링과 무관한 값을 저장하거나 DOM 요소를 조작해야 할 때 유용하며, 성능 최적화에도 큰 도움을 줍니다. 실무에서는 DOM 접근, 렌더링 횟수 추적, 이전 값 저장, 외부 라이브러리 통합 등 다양한 상황에서 활용할 수 있습니다. useRef
를 적절히 활용하면 React 애플리케이션의 성능과 유지보수성을 크게 향상시킬 수 있습니다.
