React 19가 추구하는 개발자 경험 향상의 여정은, 개발자들이 거의 매일같이 마주하지만 무심코 넘어갔던 또 하나의 보일러플레이트 코드에 가닿았다. 바로 forwardRef였다.
ref는 React에서 DOM 노드나 클래스 컴포넌트 인스턴스에 직접 접근해야 할 때 사용하는 강력한 도구였다. 주로 포커스 관리, 미디어 재생, 또는 DOM 요소의 크기 측정 같은 작업에 필수적이었다.
문제는 함수 컴포넌트가 ref를 prop처럼 직접 받을 수 없다는 점이었다. 함수 컴포넌트는 ref라는 이름의 prop을 받지 못하도록 설계되었기 때문이다. 이 제약을 우회하기 위해, React는 forwardRef라는 고차 컴포넌트(HOC, Higher-Order Component)를 제공했다.
// The Old Way with forwardRef
import { forwardRef } from 'react';
const MyInput = forwardRef(function MyInput(props, ref) {
return <input {...props} ref={ref} />;
});
// 사용하는 곳
function Form() {
const inputRef = useRef(null);
return <MyInput ref={inputRef} />;
}
이 코드는 동작했지만, 명백히 번거로웠다. 개발자는 ref를 전달받기 위해 컴포넌트 전체를 forwardRef로 감싸야 했고, 함수의 인자로 props와 ref를 따로 받아야 했다. 이는 코드의 가독성을 해치고, 특히 초심자들에게는 ref의 동작 원리를 이해하기 어렵게 만드는 장벽으로 작용했다.
“왜 함수 컴포넌트는 ref를 바로 받으면 안 되는 걸까요?”
개발자 경험 개선 회의에서 한 엔지니어가 근본적인 질문을 던졌다.
“초창기에는 ref가 특별한 예약어처럼 취급되었기 때문입니다. 하지만 이제 함수 컴포넌트가 React의 표준이 된 지금, 이 제약은 더 이상 유효하지 않을 수 있습니다. 이것은 역사적인 유물일 뿐이죠.”
그의 말처럼, forwardRef는 함수 컴포넌트 시대에 남겨진 클래스 컴포넌트 시대의 흔적과도 같았다. 팀은 이 불필요한 복잡성을 제거하기로 결정했다. 개발자가 더 자연스럽고 직관적으로 ref를 다룰 수 있게 만들어야 했다.
React 19에서는 함수 컴포넌트의 동작 방식이 변경되었다. 이제 ref는 더 이상 예약어가 아니었다. 다른 prop들과 마찬가지로, props 객체를 통해 자연스럽게 전달받을 수 있게 되었다.
이 변화로 인해, forwardRef는 더 이상 필요 없게 되었다.
// The New Way in React 19
// forwardRef가 필요 없다!
function MyInput({ ref, ...props }) {
return <input {...props} ref={ref} />;
}
// 사용하는 곳 (동일)
function Form() {
const inputRef = useRef(null);
return <MyInput ref={inputRef} />;
}
결과는 놀라울 정도로 깔끔했다.
컴포넌트 정의는 forwardRef의 래핑 없이 간결해졌고, ref는 이제 id나 className처럼 일반적인 prop 중 하나로 취급되었다. 개발자는 더 이상 forwardRef라는 추가적인 개념을 배우거나 사용할 필요가 없었다.
이것은 서버 컴포넌트나 동시성 같은 거대한 패러다임 변화는 아니었다. 하지만 개발자가 매일같이 마주하는 작은 불편함을 제거하는, 사려 깊은 개선이었다.
forwardRef와의 작별.
이것은 React 19가 개발자의 코드를 더 단순하고, 더 읽기 쉽게 만들겠다는 약속을 지키고 있음을 보여주는 또 하나의 증거였다. 불필요한 보일러플레이트가 하나씩 사라질수록, 개발자들은 React의 본질적인 아름다움에 더 가까이 다가갈 수 있게 될 터였다.


