React의 함수형 컴포넌트에서 useRef는 매우 유용한 훅입니다. 주로 DOM 요소에 직접 접근하거나, 렌더링에 영향을 주지 않는 값을 관리할 때 사용됩니다. 이번에는 useRef의 기본 사용법과 이를 활용한 예제들을 다뤄 보겠습니다.
useRef란 무엇인가?
useRef는 기본적으로 객체를 반환하는 훅입니다. 이 객체는 current라는 속성을 가지며, 이 속성에 값을 저장할 수 있습니다. useRef는 값을 변경해도 컴포넌트가 다시 렌더링되지 않기 때문에, 렌더링에 영향을 주지 않고 값이나 DOM 요소를 계속 추적할 수 있습니다.
useRef의 주요 사용 사례
- DOM 요소 접근
useRef는 함수형 컴포넌트에서 DOM 요소를 직접 접근하고 조작할 수 있게 해줍니다. - 렌더링에 영향을 주지 않는 값 추적
상태(useState)와 달리 useRef는 값을 변경해도 컴포넌트가 다시 렌더링되지 않으므로, 렌더링을 최적화할 수 있습니다.
1. useRef로 포커스 제어하기
먼저, 숫자를 입력하고 목록에 추가하는 예제를 통해 useRef의 활용법을 살펴보겠습니다.
Average 컴포넌트 (리스트 추가 및 포커스 제어)
import { useRef, useState } from "react";
export default function Average() {
const [number, setNumber] = useState('');
const [list, setList] = useState([]);
// 숫자 입력 값 변경 함수
const changeNumber = e => setNumber(e.target.value);
// 리스트에 숫자 추가 및 입력창 초기화, 포커스 설정
const changeList = () => {
// const newList = [...list, number];
const newList = list.concat(number);
setList(newList);
setNumber(''); // 입력창 초기화
refNumber.current.focus(); // 입력창에 포커스
};
// useRef를 이용해 input에 접근
const refNumber = useRef();
return (
<>
<input
ref={refNumber}
type="number"
value={number}
onChange={changeNumber}
/>
<button onClick={changeList}>등록</button>
<ul>
{list.map((v, i) => <li key={i}>{v}</li>)}
</ul>
</>
);
}
코드 설명
- useRef를 사용하여 input 요소에 대한 참조를 생성합니다.
- refNumber.current.focus()로 리스트에 숫자를 추가한 후, 입력창으로 포커스를 자동으로 이동시킵니다.
- list에 숫자가 추가되면 입력창은 비워지고, 포커스는 다시 input에 이동합니다
2. useRef와 렌더링 횟수 추적
useRef는 값이 변경되어도 컴포넌트를 리렌더링하지 않기 때문에, 렌더링 횟수나 변경된 값을 추적하는 데 유용합니다. 이를 통해, 상태가 변경되더라도 불필요한 렌더링을 방지할 수 있습니다.
useRef로 렌더링 횟수 추적하고 다른 방법과 비교하기.
import { useEffect, useRef, useState } from "react";
// 지역 변수를 이용해서 렌더링 회수를 체크 ⇒ 렌더링 마다 초기화되어 값을 유지할 수 없음
export const ChangeCountWithLocalVariable = () => {
const [message, setMessage] = useState('');
let count = 0;
console.log("#1", message);
useEffect(() => {
console.log("렌더링되었습니다.");
count++;
});
return (
<>
<h1>지역 변수를 사용하는 경우</h1>
<h2>렌더링 회수: {count}</h2>
<input type="text" value={message} onChange={e => setMessage(e.target.value)} />
</>
);
};
// 상태 변수를 이용해서 렌더링 회수를 체크 ⇒ 렌더링 되어도 값은 유지되나, 값이 변경되면 렌더링이 발생생
export const ChangeCountWithStateVariable = () => {
const [message, setMessage] = useState('');
const [count, setCount] = useState(0);
console.log("#2", message);
useEffect(() => {
console.log("렌더링되었습니다.");
setCount(count + 1);
}, [message]);
return (
<>
<h1>상태 변수를 사용하는 경우</h1>
<h2>렌더링 회수: {count}</h2>
<input type="text" value={message} onChange={e => setMessage(e.target.value)} />
</>
);
};
// ref 변수를 이용해서 렌더링 회수를 체크 ⇒ 값이 변경되어도 렌더링되지 않고, 계속해서 값이 유지됨
export const ChangeCountWithRefVariable = () => {
const [message, setMessage] = useState('');
const count = useRef(0);
console.log("#3", message);
useEffect(() => {
console.log("렌더링되었습니다.");
count.current++;
});
return (
<>
<h1>ref 변수를 사용하는 경우</h1>
<h2>렌더링 회수: {count.current}</h2>
<input type="text" value={message} onChange={e => setMessage(e.target.value)} />
</>
);
};
이 때 app.js는 아래와 같습니다.
import React from "react";
import {ChangeCountWithLocalVariable,
ChangeCountWithStateVariable,
ChangeCountWithRefVariable} from './Average';
function App() {
return (
<>
<ChangeCountWithLocalVariable />
<ChangeCountWithStateVariable />
<ChangeCountWithRefVariable />
</>
);
}
export default App;
코드 설명
- count는 useRef를 사용하여 렌더링 횟수를 추적하는 데 사용됩니다.
- useEffect 훅을 이용해 컴포넌트가 렌더링될 때마다 count.current 값을 증가시킵니다.
- 이 방식은 렌더링 횟수를 추적하면서도, count 값이 변경되어도 컴포넌트가 리렌더링되지 않음을 확인할 수 있습니다.
3. useRef로 타이머 관리하기
타이머 기능을 구현하면서, useRef를 사용하여 setInterval의 ID를 추적하고 이를 통해 타이머의 시작 및 중지 기능을 제어할 수 있습니다.
타이머 컴포넌트 구현
import { useRef, useState } from "react";
export const ChangeCountWithRefVariable = () => {
const [count, setCount] = useState(0);
const intervalId = useRef(0);
console.log(`렌더링 .... count: ${count}, intervalId: ${intervalId.current}`);
const startCount = () => {
intervalId.current = setInterval(() => setCount(count => count + 1), 1000);
console.log(`카운트 시작 ... intervalId: ${intervalId.current}`);
};
const stopCount = () => {
clearInterval(intervalId.current);
console.log(`카운트 중지 ... intervalId: ${intervalId.current}`);
};
return (
<>
<h1>카운트: {count}</h1>
<button onClick={startCount}>카운트 시작</button>
<button onClick={stopCount}>카운트 중지</button>
</>
);
};
export const ChangeCountWithLocalVariable = () => {
const [count, setCount] = useState(0);
let intervalId = 0;
console.log(`렌더링 .... count: ${count}, intervalId: ${intervalId}`);
const startCount = () => {
intervalId = setInterval(() => setCount(count => count + 1), 1000);
console.log(`카운트 시작 ... intervalId: ${intervalId}`);
};
const stopCount = () => {
clearInterval(intervalId);
console.log(`카운트 중지 ... intervalId: ${intervalId}`);
};
return (
<>
<h1>카운트: {count}</h1>
<button onClick={startCount}>카운트 시작</button>
<button onClick={stopCount}>카운트 중지</button>
</>
);
};
코드 설명
- intervalId는 useRef를 사용하여 setInterval 함수의 ID를 추적합니다.
- startCount 함수에서 타이머를 시작하고, stopCount 함수에서 타이머를 중지합니다.
- useRef로 intervalId를 관리하면, intervalId가 변경되어도 컴포넌트가 리렌더링되지 않으므로, 불필요한 렌더링을 방지할 수 있습니다.
- 위 내용은 ref로 작성한 내용만이 제대로 스탑이 작동하는 것을 볼 수 있습니다.
useRef는 React에서 매우 유용한 훅으로, DOM 요소에 접근하거나 렌더링에 영향을 주지 않는 값을 추적할 때 사용됩니다. 특히 DOM을 제어하거나 타이머, 이전 상태 추적 등 다양한 기능에서 유용하게 활용할 수 있습니다
*생성형 AI 활용한 클라우드&보안 전문가 양성캠프 과정의 교육내용 정리 자료입니다.
'코딩 > 리액트' 카테고리의 다른 글
[새싹 성동 2기] useReducer를 활용한 상태 관리 (0) | 2024.12.06 |
---|---|
[새싹 성동 2기] 리액트 앱에서 국가와 국기 정보를 출력하는 방법 (1) | 2024.11.19 |
[새싹 성동 2기] React에서 Hooks (useState와 useEffect) 사용하기 (0) | 2024.11.19 |
[새싹 성동 2기] React 컴포넌트 라이프사이클과 메서드 활용하기 (1) | 2024.11.19 |
[새싹 성동 2기]React에서 스크롤 박스 구현하기 (0) | 2024.11.19 |