React 19로 올리면서 forwardRef랑 작별하고, 메타태그를 컴포넌트에서 박았다
React 19가 바꾼 것 — ref, Actions, 그리고 네이티브 메타태그
#React #프론트엔드 #리팩토링
얼마 전에 SPA 메타태그를 서버에서 직접 박아넣는 글을 썼다. 그 글을 쓰고 나서 React 19를 보다가, React가 이제 메타태그를 컴포넌트에서 직접 지원한다 는 걸 알게 됐다. 그래서 18에 멈춰 있던 블로그를 19로 올렸다. 이 글에선 React 19가 18에서 뭘 바꿨는지, 그리고 그게 내 코드를 어떻게 줄여줬는지 정리해본다. 메타태그를 컴포넌트에서 그냥 렌더한다 이게 제일 먼저 와닿았다. React 19에선 컴포넌트 안에서 title 이나 meta 를 그냥 렌더하면, React가 알아서 그걸 문서의 head 로 끌어올린다 . react-helmet 같은 라이브러리를 안 써도 된다. function BlogPost({ post }) { return ( article title {post.title} | Jaeyonging 블로그 /title meta name="description" content={post.descr} / meta property="og:title" content={post.title} / h1 {post.title} /h1 {/* ... 본문 ... */} /article ); } 근데 여기서 헷갈리면 안 되는 게 있다. 이건 자바스크립트가 돌고 난 뒤에 박히는 거다. 즉 크롤러나 카톡 봇은 여전히 못 본다. 그래서 내가 서버에서 메타를 주입한 작업(지난 글)이 여전히 필요하다 . 둘은 경쟁이 아니라 보완이다 — 사람 브라우저용은 React 19가, 크롤러용은 서버 주입이 맡는다. forwardRef랑 작별했다 React 18까지는 자식 컴포넌트한테 ref를 넘기려면 forwardRef 로 감싸야 했다. 이게 은근 거추장스러웠다. React 19부턴 ref를 그냥 일반 prop처럼 받는다. // React 18 — forwardRef로 감싸야 했음 const Input = forwardRef((props, ref) = { return input ref={ref} {...props} / ; }); // React 19 — 그냥 prop으로 받으면 끝 function Input({ ref, ...props }) { return input ref={ref} {...props} / ; } forwardRef로 감싸던 컴포넌트들을 풀고 나니 코드가 한 겹씩 얇아졌다. 별거 아닌 것 같아도, 이런 래퍼가 쌓이면 컴포넌트 트리를 읽기 힘들어진다. Actions — 폼의 로딩/에러 상태를 React가 들고 있어준다 이게 18에서 19로 오면서 제일 크게 바뀐 부분이다. 예전엔 폼 제출할 때 isLoading 이랑 error 상태를 내가 직접 useState로 만들고, try/catch로 일일이 켜고 껐다. React 19는 비동기 함수를 폼의 action에 그냥 넘기면, pending(처리 중)이랑 error를 자동으로 관리 해준다. useActionState, useFormStatus, useOptimistic 같은 훅이 같이 들어왔다. // 제출 중 상태를 내가 안 만들어도 됨 const [error, submitAction, isPending] = useActionState( async (prev, formData) = { const res = await save(formData); if (res.error) return res.error; return null; }, null ); // form action={submitAction} 만 걸면 isPending 자동 내가 손으로 관리하던 "제출 중이니 버튼 비활성화" 같은 코드가 통째로 사라졌다. 특히 useOptimistic은, 서버 응답을 기다리기 전에 화면을 먼저 바꿔놓고(낙관적 업데이트) 실패하면 되돌리는 걸 쉽게 해준다. use() 훅 promise를 렌더 중에 직접 풀 수 있는 use() 도 들어왔다. Suspense랑 같이 쓰면 데이터를 await하듯 받아올 수 있다. 조건문 안에서도 호출할 수 있어서, 기존 훅 규칙보다 유연하다. 정리하면 React 18 → 19 업글에서 느낀 건, 새 버전이 "기능을 추가" 한다기보다 "내가 손으로 하던 보일러플레이트를 프레임워크가 가져간다" 는 거였다. forwardRef 래퍼, isLoading 수동 관리, 메타태그 라이브러리 — 다 내가 했던 잡일인데, 19가 하나씩 흡수했다. 덕분에 코드가 눈에 띄게 줄었다. 메이저 업글은 늘 무섭지만, 줄어든 코드량을 보면 올릴 가치가 있었다. 메타태그 부분은 지난 SEO 글이랑 같이 보면 "사람용/크롤러용"이 어떻게 갈리는지가 더 선명할 거다.