React 19가 가져온 수많은 거대한 변화들 속에서, 비교적 작지만 수많은 개발자들의 일상을 확실하게 바꿔줄 또 하나의 개선이 조용히 확정되었다. 그것은 바로 forwardRef라는, 오랜 시간 개발자들을 괴롭혀 온 보일러플레이트 코드와의 작별이었다.
개발자 경험(DX) 팀의 한 엔지니어는 팀 회의에서 forwardRef가 초래하는 현실적인 문제들을 다시 한번 상기시켰다.
“forwardRef는 세 가지 측면에서 개발자의 흐름을 방해합니다.”
그는 화이트보드에 forwardRef를 사용한 코드를 적으며 설명했다.
“첫째, 가독성입니다. 컴포넌트의 본질적인 로직이 forwardRef라는 한 겹의 함수로 감싸여 있어 코드를 파악하기 어렵게 만듭니다. 컴포넌트의 이름조차 displayName을 따로 설정해주지 않으면 개발자 도구에서 익명 함수로 표시되기도 하죠.”
“둘째, 타입스크립트(TypeScript)와의 궁합입니다. forwardRef를 사용하는 컴포넌트에 정확한 타입을 입히는 것은 매우 까다롭고 장황합니다. 수많은 제네릭 타입과 React.ForwardRefRenderFunction 같은 복잡한 타입을 사용해야만 하죠. 많은 개발자가 여기서 타입 에러와 싸우다 시간을 허비합니다.”
“셋째, 인지적 부담입니다. ref는 왜 props가 아닌 별개의 인자로 전달되는가? 함수 컴포넌트는 왜 ref를 직접 받을 수 없는가? 이 ‘왜’라는 질문에 답하기 위해 개발자는 React의 역사와 내부 구현의 미묘한 부분까지 이해해야만 합니다. 이것은 명백한 진입 장벽입니다.”
그의 발표는 팀원들의 깊은 공감을 얻었다. forwardRef는 더 이상 유지할 명분이 없는, 구시대의 기술적 부채였다.
React 19에서 ref가 일반 prop처럼 전달될 수 있도록 핵심 로직이 변경되면서, 이 모든 문제는 눈 녹듯 사라졌다.
forwardRef로 감싸여 있던 코드는 이제 평범한 함수 컴포넌트 선언으로 돌아왔다.
// Before
const MyInput = forwardRef((props, ref) => {
// ...
});
// After
function MyInput({ ref, ...props }) {
// ...
}
이 작은 변화가 가져온 효과는 기대 이상이었다.
- 컴포넌트의 정의가 간결해지고, 코드의 의도가 명확해졌다.
- 타입스크립트 환경에서
refprop의 타입을 정의하는 것이 다른 어떤 prop처럼 단순해졌다. - 개발자는 더 이상
ref를 특별 취급할 필요 없이, 다른 모든props와 동일한 멘탈 모델로 다룰 수 있게 되었다.
릴리스를 앞두고, 공식 업그레이드 가이드에는 다음과 같은 문장이 추가되었다.
“React 19부터, 함수 컴포넌트는 ref를 prop으로 직접 받을 수 있습니다. 따라서 대부분의 경우 forwardRef는 더 이상 필요하지 않습니다. 기존 코드에서 forwardRef를 제거하는 것을 권장합니다.”
이것은 작지만 확실한 개발자 경험의 승리였다.
서버 컴포넌트나 동시성 같은 거대한 혁신이 도시의 스카이라인을 바꾸는 대규모 공사였다면, forwardRef의 제거는 매일 걷는 길의 울퉁불퉁한 보도블록 하나를 매끄럽게 교체하는 것과 같은 세심한 배려였다. 그리고 때로는 이런 작은 배려가 개발자의 하루를 바꾸고, 생산성을 극적으로 향상시키는 가장 확실한 방법이 되기도 했다.
React 19는 개발자들의 가장 사소한 고통까지도 외면하지 않겠다는 약속을, 이 조용한 작별 인사를 통해 다시 한번 증명하고 있었다.


