useRef란?
useRef는 렌더링에 필요하지 않은 값을 참조할 수 있는 React Hook입니다.
const ref = useRef(initialValue);
기본 규칙
컴포넌트의 최상위 레벨에서 useRef를 호출하여 ref를 선언합니다.
import { useRef } from 'react';
function MyComponent() {
const intervalRef = useRef(0);
const inputRef = useRef(null);
// ...
매개변수
useRef는 단일한 매개변수를 받습니다. 해당 매개변수는 ref 객체의 current 프로퍼티의 초기 설정값입니다. 어떠한 유형의 값이든 지정할 수 있으며, 해당 인자는 초기 렌더링 이후부터는 무시됩니다.
반환값
useRef는 단일 프로퍼티(current)를 가진 객체를 반환합니다. 처음 전달한 initialValue로 설정되며, 나중에 다른 값으로 바꿀 수 있습니다. ref 객체를 jsx 노드의 ref attribute로 React에 전달하면 React는 current 프로퍼티를 설정합니다. 다음 렌더링에서 useRef는 동일한 객체를 반환합니다.
즉, useRef는 useState와 마찬가지로 컴포넌트의 렌더링 시에 데이터를 저장할 수 있습니다. 하지만 useState와 다르게 데이터를 변경할 때 state는 set함수를 호출하며 해당 컴포넌트를 리렌더링 하지만, useRef의 current는 변경이 일어나도 리렌더링하지 않습니다.
주의사항
- ref.current는 React의 렌더링 사이클에 직접적인 영향을 주지 않습니다. 따라서 ref.current에 렌더링에 필요한 상태 정보를 저장하고 이를 직접 변경하는 것은 React의 상태 관리 및 렌더링 원칙에 어긋납니다. 이렇게 하면 예기치 않은 버그가 발생할 수 있습니다.
- 초기화를 제외하고는 렌더링 중에 ref.current를 쓰거나 읽지 마세요. 이렇게 하면 컴포넌트의 동작을 예측할 수 없게 됩니다. React는 state의 변경은 관측하지만 ref.current의 변경은 알 수 없습니다.
- React의 렌더링 함수는 순수 함수처럼 동작해야 합니다. 같은 props와 state를 입력으로 받으면 같은 출력을 반환해야합니다. 하지만 렌더링에 ref.current를 읽거나 쓰게 되면 이 순수성을 위반하게 됩니다.
ref는 state와 마찬가지로 렌더링 사이의 데이터를 저장할 수 있지만, 값을 변경할 때 리렌더링을 촉발하지 않습니다. 따라서 ref는 시각적 출력에 영향을 미치지 않는 정보를 저장하는데 적합합니다.
function handleStartClick() {
const intervalId = setInterval(() => {
// ...
}, 1000);
intervalRef.current = intervalId;
}
function handleStopClick() {
const intervalId = intervalRef.current;
clearInterval(intervalId);
}
ref는 내부의 값을 업데이트하려면 current 프로퍼티를 수동으로 변경해야 합니다.
ref를 사용하면 다음을 보장합니다.
- 리렌더링 사이에 정보를 저장할 수 있습니다.
- 변경해도 리렌더링을 촉발하지 않습니다.
- 각각의 컴포넌트에 로컬로 저장됩니다.
ref로 DOM 조작하기
ref는 주로 DOM을 조작할 때 사용됩니다. React는 이를 위한 기본 지원이 있습니다.
import { useRef } from 'react';
function MyComponent() {
const inputRef = useRef(null);
// ...
// ...
return <input ref={inputRef} />;
초기값을 null로 설정한 ref 객체를 조작하려는 DOM 노드의 JSX에 ref attribute로 전달합니다.
React가 DOM 노드를 생성하고 화면에 그린 후, React는 ref 객체의 current 프로퍼티를 DOM 노드로 설정합니다. 이제 DOM 노드 <input>에 접근해 focus()와 같은 HTMLElement 메서드를 호출할 수 있습니다.
ref 콘텐츠 재생성 피하기
React는 초기에 ref 값을 한 번 저장하고, 다음 렌더링부터는 이를 무시합니다.
function Video() {
const playerRef = useRef(new VideoPlayer());
// ...
new VideoPlayer()의 결과는 초기 렌더링에만 사용되는 것이지만, 호출 자체는 이후의 모든 렌더링에서도 여잔히 계속 이루어지기 때문에 최적화 문제가 발생할 수 있습니다. 이 문제를 해결하려면 대신 다음과 같이 ref를 초기화할 수 있습니다.
function Video() {
const playerRef = useRef(null);
if (playerRef.current === null) {
playerRef.current = new VideoPlayer();
}
// ...
일반적으로 렌더링 중에 ref.current를 쓰거나 읽는 것은 허용되지 않습니다. 하지만 이 경우에는 결과가 항상 동일하고 초기화 중에만 조건이 실행되므로 충분히 예측할 수 있어서 괜찮습니다.
커스텀 컴포넌트에 ref 전달하기
컴포넌트에 ref를 전달하고자 다음과 같이 하면
const inputRef = useRef(null);
return <MyInput ref={inputRef} />;
다음과 같은 오류가 발생합니다.
경고: 함수 컴포넌트에는 ref를 지정할 수 없습니다. 이 ref에 접근하려는 시도는 실패합니다. React.forwardRef()를 사용하려고 하셨나요?
기본적으로 컴포넌트는 내부의 DOM 노드에 대한 ref를 외부로 노출하지 않습니다.
이 문제를 해결하려면 ref를 가져오고자 하는 컴포넌트를 찾은 후, forwardRef로 감싸면 부모 컴포넌트에서 ref를 가져올 수 있습니다.
import { forwardRef } from 'react';
const MyInput = forwardRef(({ value, onChange }, ref) => {
return (
<input
value={value}
onChange={onChange}
ref={ref}
/>
);
});
export default MyInput;
해당 게시글은 리액트 공식 문서를 정리한 글입니다. 자세한 내용은 아래의 링크를 참고해 주세요. :)
https://ko.react.dev/reference/react/useRef
useRef – React
The library for web and native user interfaces
ko.react.dev
'WEB > REACT' 카테고리의 다른 글
useMemo (0) | 2024.06.19 |
---|---|
useCallback (0) | 2024.06.18 |
useEffect (0) | 2024.06.18 |
useState (0) | 2024.06.16 |
REACT란 무엇인가? (0) | 2023.07.08 |