[React] useRef

0

React

목록 보기
3/6

useRef

useRef는 렌더링에 필요하지 않은 값을 참조할 수 있게 해주는 React Hook입니다.

const ref = useRef(initialValue)

Reference

useRef(initialValue)

컴포넌트의 최상위 수준에서 useRef를 호출하여 ref를 선언합니다.

import { useRef } from 'react';

function MyComponent() {
  const intervalRef = useRef(0);
  const inputRef = useRef(null);
  // ...

Parameters

initialValue: ref 객체의 current 속성이 처음에 가질 값을 의미합니다. 어떤 타입의 값도 가능합니다. 이 인수는 초기 렌더링 이후에는 무시됩니다.

Returns

useRef는 하나의 속성을 가진 객체를 반환합니다.

  • current: 초기에는 전달한 initialValue으로 설정됩니다. 이후에 다른 값으로 설정할 수 있습니다. JSX 노드에 ref 속성으로 ref 객체를 React에 전달하면, React는 그것의 current 속성을 설정합니다.

다음 렌더링에서도 useRef 는 동일한 객체를 반환합니다.

Caveats

  • ref.current 속성을 변경할 수 있습니다. 상태와는 달리 변경 가능합니다. 그러나 렌더링에 사용되는 객체(예: 상태의 일부)를 보유하고 있다면 해당 객체를 변경해서는 안됩니다.

  • ref.current 속성을 변경하면 React는 컴포넌트를 다시 렌더링하지 않습니다. ref는 일반 JavaScript 객체이기 때문에 변경 사항이 언제 발생했는지에 대해 React는 인식하지 못합니다.

  • 초기화를 제외하고 렌더링 중에는 ref.current를 쓰거나 읽지 마세요. 그렇게 하면 컴포넌트의 동작이 예측할 수 없게 됩니다.

  • Strict Mode에서는 React가 부수 효과를 찾아주기 위해 컴포넌트 함수를 두 번 호출합니다. 이는 개발용으로만 사용되며 프로덕션에는 영향을 미치지 않습니다. 각 ref 객체는 두 번 생성되지만 한 버전은 버려집니다. 컴포넌트 함수가 순수 함수(되어야 할 것)인 경우 이러한 동작이 동작에 영향을 미치지 않아야 합니다.


Usage

Referencing a value with a ref

하나 이상의 ref를 선언하기 위해 컴포넌트의 최상위 수준에서 useRef 를 호출하세요.

import { useRef } from 'react';

function Stopwatch() {
  const intervalRef = useRef(0);
  // ...

useRef 는 초기에 전달한 초기값으로 설정된 단일 current 속성을 가진 ref 객체를 반환합니다.

다음 렌더링에서도 useRef 는 동일한 객체를 반환합니다. current 속성을 변경하여 정보를 저장하고 나중에 읽을 수 있습니다. 이것은 state 를 생각나게 할 수 있지만, 중요한 차이점이 있습니다.

ref를 변경한다고 다시 렌더링되지 않습니다. 이는 ref가 컴포넌트의 시각적 출력에 영향을 주지 않는 정보(화면에 표현되지 않는 정보)를 저장하기에 이상적이라는 것을 의미합니다. 예를 들어, 인터벌 ID를 저장하고 나중에 검색해야하는 경우 ref에 넣을 수 있습니다. ref 내부의 값을 업데이트하려면, 해당 ref의 current 속성을 수동으로 변경해야 합니다.

function handleStartClick() {
  const intervalId = setInterval(() => {
    // ...
  }, 1000);
  intervalRef.current = intervalId;
}

나중에 ref에서 해당 인터벌 ID를 읽어와 해당 인터벌을 지우기 위해 clearInterval을 호출할 수 있습니다.

function handleStopClick() {
  const intervalId = intervalRef.current;
  clearInterval(intervalId);
}

ref를 사용하면 다음과 같은 것을 보장할 수 있습니다.

  • 일반 변수와 달리, ref를 사용하여 다시 렌더링 사이에 정보를 저장할 수 있습니다.
  • ref를 변경하면, 상태 변수와는 달리 다시 렌더링이 트리거되지 않습니다.
  • ref를 통해 저장된 정보는 각 컴포넌트의 복사본에 로컬하게 유지됩니다. (외부 변수와는 다르게 공유되지 않습니다.)

ref를 변경하면 다시 렌더링이 트리거되지 않으므로, 화면에 표시하려는 정보를 저장하기에는 ref가 적합하지 않습니다. 대신에 상태를 사용하세요.


Manipulating the DOM with a ref

DOM 조작에 ref를 사용하는 것은 특히 흔합니다. React는 이에 대한 내장 지원을 제공합니다.

먼저, 초기 값으로 null을 가진 ref 객체를 선언하세요.

import { useRef } from 'react';

function MyComponent() {
  const inputRef = useRef(null);
  // ...

그 다음, 조작하려는 DOM 노드의 JSX에 ref 속성으로 ref 객체를 전달하세요.

// ...
return <input ref={inputRef} />;

React는 DOM 노드를 생성하고 화면에 표시한 후, ref 객체의 current 속성을 해당 DOM 노드로 설정합니다. 이제 <input>의 DOM 노드에 접근하고 focus()와 같은 메소드를 호출할 수 있습니다.

function handleClick() {
  inputRef.current.focus();
}

노드가 화면에서 제거될 때, React는 current 속성을 다시 null로 설정합니다.


Avoiding recreating the ref contents

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 를 쓰거나 읽는 것은 허용되지 않습니다. 그러나 이 경우에는 결과가 항상 동일하고, 조건은 초기화 중에만 실행되므로 완전히 예측 가능합니다. 따라서 이러한 방식으로 진행하는 것이 괜찮습니다.


출처: https://react.dev/reference/react/useRef

profile
지치지 않는 백엔드 개발자 김성주입니다 :)

0개의 댓글