본문으로 건너뛰기
개발 머꼬
개발 노트React
hohyeon.dev31

forwardRef를 걷어내도 되는 이유 — ref가 그냥 prop이 됐습니다

  • #Engineering Note
  • #React
  • #Upgrade

문제 발생

디자인 시스템의 Input처럼 DOM 요소를 감싸는 컴포넌트는 바깥에서 포커스를 주려면 ref를 통과시켜야 했고, 그 때문에 전부 forwardRef로 감싸야 했습니다.

const MyInput = forwardRef(function MyInput({ placeholder }, ref) {
  return <input placeholder={placeholder} ref={ref} />;
});

컴포넌트 하나마다 래퍼가 한 겹씩 늘고, displayName을 따로 지정해야 하며, ref를 두 개 이상 내려보내야 할 때는 방법이 없었습니다.

원인 분석

ref는 오랫동안 key와 함께 prop이 아닌 특별한 값이었습니다. JSX에 ref를 적어도 컴포넌트의 props에는 들어오지 않았고, 그래서 별도 통로인 forwardRef가 필요했습니다.

React 19에서 이 예외가 없어졌습니다. 함수 컴포넌트에서 ref는 그냥 props의 한 항목입니다.

새로 만드는 함수 컴포넌트는 더 이상 forwardRef가 필요 없고, 앞으로의 버전에서 forwardRef는 deprecated 후 제거될 예정입니다.

해결 방안

  1. 래퍼를 벗기고 props에서 꺼내 씁니다.
function MyInput({ placeholder, ref }) {
  return <input placeholder={placeholder} ref={ref} />;
}

<MyInput ref={inputRef} placeholder="이름" />
  1. ref를 여러 개 내려보낼 수 있습니다. 이름이 자유로우니 특별 취급받는 ref 외에 추가 참조를 얼마든지 정의할 수 있습니다.
function Field({ inputRef, labelRef, label }) {
  return (
    <>
      <label ref={labelRef}>{label}</label>
      <input ref={inputRef} />
    </>
  );
}
  1. 클래스 컴포넌트에는 해당되지 않습니다. 이 변경은 함수 컴포넌트 이야기입니다.
  2. 한 번에 다 바꾸지 않아도 됩니다. forwardRef는 19에서도 그대로 동작하므로, 새로 만드는 컴포넌트부터 적용하고 기존 것은 공식 codemod로 정리하면 됩니다.
  3. 타입을 함께 정리합니다. TypeScript에서는 forwardRef의 제네릭 두 개 대신 props 인터페이스에 ref를 넣으면 되므로 시그니처가 눈에 띄게 짧아집니다.
interface MyInputProps {
  placeholder?: string;
  ref?: React.Ref<HTMLInputElement>;
}

공식 문서

마지막 수정

좋아요북마크

댓글0

아직 댓글이 없어요. 첫 의견을 편하게 남겨 보세요.