I code, therefore I exist.

웹 프론트 엔드 개발을 공부하고 있는 Ocean이라고 합니다. 만나서 반갑습니다.

WEB/REACT

useRef

Ocean 2024. 6. 17. 17:59

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