[리액트 공식 문서 번역] useRef

버건디·2023년 3월 7일
0

리액트 공식 문서

목록 보기
3/4

원 글 링크

useRef

useRef 는 당신이 렌더링이 필요 없는 값을 참조 할수 있도록 하는 리액트 훅입니다.

const ref = useRef(initialValue)

useRef(initialValue)

ref를 선언하기 위해서 당신의 컴포넌트 최상단에서 useRef를 호출하세요.

import { useRef } from 'react';

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

파라미터들

  • initialValue : 당신이 ref 객체의 current 프로퍼티에 초기에 지정하고 싶은 값입니다.

어떠한 타입의 값도 될 수 있습니다. 이 인자는 초기 렌더링 후에 무시되어집니다.

반환값들

useRef 는 단일 프로퍼티 객체를 반환합니다.

  • current : 초반에는 당신이 전달한 초기 값으로 설정되어집니다. 나중에 다른 값을 지정할 수 있습니다. 만약 당신이 JSX 노드에 대한 ref 속성으로서 리액트에게 ref 객체를 전달한다면, 리액트는 그것을 current 프로퍼티로 지정할 것입니다.

다음 렌더링 과정에서, useRef 는 같은 객체를 리턴합니다.

주의사항들

  • 당신은 ref.current 프로퍼티 값을 수정할수 있습니다. state 값과는 다르게, 하지만 그 프로퍼티 값이 렌더링을 위해서 사용되는 값이라면 ( 예를 들어서, state의 한 부분) 그렇다면 그 객체를 수정해서는 안됩니다.
  • ref.current 프로퍼티 값을 변경할때, 리액트는 당신의 컴포넌트를 리렌더 하지 않습니다. ref는 일반 자바스크립트 객체이기 때문에, 당신이 ref 값을 변경할때 리액트는 그것을 알아차리지 못합니다.
  • 초기화를 제외하고는 렌더링 동안에 ref.current 값을 읽거나 쓰지 마십시오. 이러한 행위는 컴포넌트의 행동을 예측불가능하게 만듭니다.
  • Strict Mode에서, 리액트는 방해되는 요소들을 찾기위해서 당신의 컴포넌트를 2번 호출합니다.
    이것은 오직 개발환경에서만 유효한 행위로써, 배포 환경에는 영향을 끼치지 못합니다. 이건 각각의 ref 객체가 2번 생성되었다가 2개중에 한개는 나중에 제거된다는 것을 의미합니다. 만약 너의 컴포넌트가 순수한 상태를 유지해야한다거나, 순수한 상태라면 2번 호출하는 것은 당신의 컴포넌트에 영향을 주지 않습니다.

사용

ref 를 이용한 값 참조

하나 그 이상의 ref 들을 선언하기 위해서 당신의 컴포넌트 최상단에서 useRef를 호출하세요.

import { useRef } from 'react';

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

useRef는 당신이 설정한 초기값을 가지고 있는 current 프로퍼티를 가지고 있는 ref 객체를 반환합니다.

다음 렌더링에서, useRef는 같은 객체를 반환합니다.

당신은 값을 나중에 불러들이거나 저장하기 위해서 current 프로퍼티를 변경할 수 있습니다.

이건 state와 비슷해보이는데, 이 둘 간에는 중요한 차이점이 있습니다.

ref 를 변경하는 것은 리렌더를 유발하지 않습니다.

이건 ref 가 당신의 컴포넌트의 시각적인 부분들에 영향을 끼치지 않고 값들을 완벽히 저장한다는 것을 의미합니다.

예를 들어서, 만약에 당신이 setInterval 값을 저장해두었다가 나중에 사용해야한다면, 그 값을 ref에 넣어둘 수 있습니다.

ref 안에 있는 값을 업데이트 하기 위해서, 당신은 수동적으로 current 프로퍼티 값을 변경 시켜주어야 합니다.

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

후에, 당신은 clearInterval 를 호출하기 위해서 ref 로부터 setInterval 값을 읽어올 수 있습니다.

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

ref 를 사용함으로써, 당신은

  • 리렌더들 사이에서 값들을 저장할 수 있습니다. (매 렌더링을 유발하는 규칙적인 변수들과는 다르게)
  • ref 값을 변경한다고 리렌더를 유발하지 않습니다. (리렌더링을 유발하는 state 변수들과는 다르게)
  • 이 값들은 밖에서 공유되는 변수들과는 다르게 당신의 컴포넌트 내에서 각각 로컬에 적용됩니다.

ref 는 리렌더를 유발하지 않기때문에, 브라우저 화면상에서 보여지게 하고픈 값을 저장하기에는 부적절합니다.

그러한 조건이라면 state를 사용하는 것이 옳습니다.

useRef 와 useState 둘중에 무엇을 선택해야하는 것인지는 한번 더 읽어보십시오.

스톱워치 예시

이 예시는 state와 ref 둘다 사용합니다. startTime과 now 는 렌더링을 위해서 사용되는 state 변수들입니다.

그러나 우리는 버튼을 눌렀을때 interval 값을 초기화 할수 있도록 하기 위해서 setInterval 값을 갖고 있는 ref 가 필요합니다.

interval ID 는 렌더링에 사용되지 않기때문에, ref 안에서 관리하고 그 안에서 업데이트 하는것이 적절합니다.

주의 사항

ref.current 값을 렌더링하는 동안에 사용하거나 읽지 마십시오.

리액트는 당신의 컴포넌트의 body 가 순수함수처럼 동작하기를 바랍니다.

  • 만약 props나 state, context 의 인풋값들이 같다면, 정확하게 같은 JSX 를 리턴합니다.
  • 다른 동작이나, 다른 인자들 안에서 ref 값을 호출하는 것은 다른 호출들의 결과에 영향을 끼치지 않습니다.

렌더링 되는 동안에 Ref 값을 변경하거나 사용하는 것은 이러한 부분들을 깨뜨립니다.

function MyComponent() {
  // ...
  // 🚩 Don't write a ref during rendering
  myRef.current = 123;
  // ...
  // 🚩 Don't read a ref during rendering
  return <h1>{myOtherRef.current}</h1>;
}

당신은 대신에 이벤트 핸들러나, useEffect 를 사용함으로써 ref 값들을 수정할 수 있습니다.

function MyComponent() {
  // ...
  useEffect(() => {
    // ✅ You can read or write refs in effects
    myRef.current = 123;
  });
  // ...
  function handleClick() {
    // ✅ You can read or write refs in event handlers
    doSomething(myOtherRef.current);
  }
  // ...
}

만약 렌더링 되는 동안에 값을 변경해야한다면, useState를 사용하세요.

이러한 규칙을 무시했는데도 컴포넌트는 잘 동작할 수도 있습니다. 하지만 우리가 앞으로 리액트에 추가할 새로운 기능들의 대부분은 이러한 부분들에 의존할 것입니다. 당신의 컴포넌트를 순수한 상태로 유지하세요 를 읽어보세요.


ref 를 사용해서 DOM 조작하기

DOM을 조작하기 위해서 ref 를 사용하는 것은 매우 흔한일입니다.

리액트는 이것을 지원합니다. 첫번째로 ref 객체에 초기 값을 저장해서 선언하세요.

import { useRef } from 'react';

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

그 후에 당신이 조작하고 싶은 DOM 노드의 JSX로 ref 속성으로써의 ref 객체를 전달하세요.

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

리액트가 DOM 노드들을 만들고 그걸 브라우저 화면에 띄운 후에, 리액트는 current 프로퍼티 값을 DOM 노드에 지정합니다.

이제 당신은 input의 DOM 노드에 focus 메서드를 사용함으로써 접근할 수 있습니다.

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

ref 콘텐츠들을 재생성하는걸 피하기

리액트는 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 값을 수정하거나 읽는것은 용인되지 않습니다. 하지만, 위의 코드처럼 예측 가능하고 초기화될때 항상 같은 값을 리턴하는 경우에는 괜찮습니다.

profile
https://brgndy.me/ 로 옮기는 중입니다 :)

0개의 댓글