useRef 톺아보기

Seungrok Yoon (Lethe)·2023년 8월 8일
1

ref, forwardRef

ref, forwardRef는 제가 리액트를 공부하면서 생소하게 느낀 부분 중 하나였습니다. 특히 타입스크립트랑 같이 사용하는 경우에는 이 녀석의 타입이 MutableRefObjectRefObject로 나뉘더라구요?

그래서 ref, forwardRef를 확실히 알고 넘어가려합니다.

ref 가 뭘까요?

React공식문서 ref

ref는 DOM node를 부모 컴포넌트에 노출시켜, 부모 컴포넌트가 해당 DOM node를 직접 조작할 수 있도록 하는 리액트만의 기술입니다. 함수형 컴포넌트에서 사용을 할 때는 useRef()훅을 사용하는데요, useRef는 current 프로퍼티가 들어있는 객체를 리턴합니다.

그런데 리턴타입이 두 종류입니다. MutableRefObject, 그리고 RefObject 이렇게요.

MutableRefObject vs RefObject

MutableRefObject와 RefObject는 같은 생김새지만, current프로퍼티가 readonly라는 점이 다릅니다.

 interface MutableRefObject<T> {
        current: T;
    }
   interface RefObject<T> {
        readonly current: T | null;
    }

리액트 공식문서의 예시에서는 useRef를 null로 초기화하며 선언해주고, 리턴받은 ref를 Element의 ref 프로퍼티에 넘겨줍니다.

React will assign the current property with the DOM element when the component mounts, and assign it back to null when it unmounts. ref updates happen before componentDidMount or componentDidUpdate lifecycle methods.

예전 리액트 공식문서에 따르면 리액트는 컴포넌트가 마운트될 때, ref의 current프로퍼티에 DOM요소를 할당하고, 언마운트될 때 null을 할당합니다. ref에 대한 업데이트는 컴포넌트가 마운트되기 전(componentDidMount), 그리고 컴포넌트가 업데이트(componentDidUpdate)전 라이프사이클에서 진행이 됩니다.

이 말인 즉슨, 컴포넌트가 마운트가 완료되었거나 업데이트가 완료된 시점에는 ref.current가 초기화/또는 업데이트가 완료되어있기에 우리는 안심하고 ref.current에 접근해 값을/요소를 조작할 수 있다는 의미입니다.

import { useRef } from 'react';

export default function Form() {
  const inputRef = useRef(null);

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

  return (
    <>
      <input ref={inputRef} />
      <button onClick={handleClick}>
        Focus the input
      </button>
    </>
  );
}

그런데 이 차이가 있나요? 리액트 깃허브의 코드를 보면 별 차이가 없는 것 같아요.

forwardRef


last update: 2023.08.10

This happens because by default React does not let a component access the DOM nodes of other components. Not even for its own children! This is intentional. Refs are an escape hatch that should be used sparingly. Manually manipulating another component’s DOM nodes makes your code even more fragile.

리액트는 다른 컴포넌트의 DOM 노드에 직접적으로 접근하여 조작하는 것을 지양하는 듯 합니다. 리액트는 가상 DOM트리를 나중에 HTML과 합치기에, 직접적으로 브라우저 DOM노드에 접근하여 무분별하게 조작하는 것은 위험한 시도라는 생각이 듭니다. 그래서 sparingly(절약하여) Ref를 사용하라고 하는 것일 수 있겠네요.

여러개의 useRef를 관리해야 하는 경우

(아직 학습중입니다)
https://react.dev/learn/manipulating-the-dom-with-refs#how-to-manage-a-list-of-refs-using-a-ref-callback

useImperativeHandle 훅

(아직 학습중입니다)
https://react.dev/reference/react/useImperativeHandle

profile
안녕하세요 개발자 윤승록입니다. 내 성장을 가시적으로 기록하기 위해 블로그를 운영중입니다.

0개의 댓글