서버 컴포넌트가 데이터베이스와 직접 통신할 수 있다는 사실은 개발의 복잡성을 획기적으로 줄여주었다. 하지만 이 새로운 패러다임이 가져다준 선물은 그것뿐만이 아니었다. 팀은 곧 서버 컴포넌트가 오랫동안 그들을 괴롭혀 온 ‘하이드레이션의 역설’을 해결할 결정적인 열쇠임을 깨닫게 되었다.
세바스찬 마크바게는 제4화에서 마주했던 그 ‘죽은 화면’을 다시 떠올렸다. 서버로부터 완벽한 모습의 HTML을 전달받았음에도, 자바스크립트가 모든 준비를 마칠 때까지는 아무것도 클릭할 수 없었던 그 기묘한 상태.
그는 화이트보드에 간단한 페이지 구조를 그렸다.
<Layout> (Server Component)
<Header> (Server Component)
<MainContent>
<ProductImage> (Server Component)
<ProductDescription> (Server Component)
<AddToCartButton> (Client Component) <-- 상호작용 필요!
</MainContent>
<Footer> (Server Component)
</Layout>
이 페이지에서 유일하게 사용자의 상호작용이 필요한 것은 ‘장바구니 담기’ 버튼뿐이었다. 헤더, 푸터, 상품 이미지와 설명 등은 모두 정적인 콘텐츠였고, 따라서 서버 컴포넌트로 만들어졌다.
“기존의 SSR 방식이었다면, 우리는 이 페이지 전체가 하이드레이션될 때까지 기다려야 했지.”
세바스찬이 입을 열었다. 그의 시선은 화이트보드의 <AddToCartButton>
에 고정되어 있었다.
“하지만 이제는 아니야. 이 구조를 다시 한번 잘 봐.”
팀원들은 그의 말에 집중하며 다이어그램을 뜯어보기 시작했다. 그러자 한 가지 명백한 사실이 드러났다.
“잠깐만요….” 로렌 탄이 무언가 깨달은 듯 말했다. “서버 컴포넌트에는 애초에 이벤트 핸들러나 상태가 없잖아요. 그렇다면… 그 컴포넌트들은 하이드레이션을 할 필요가 없는 것 아닌가요?”
“정확해.”
세바스찬의 입가에 옅은 미소가 번졌다.
“생명을 불어넣을 필요가 없는 것에, 굳이 생명을 불어넣으려고 애쓸 이유가 있을까?”
그 순간, 회의실의 모든 팀원들은 거대한 깨달음에 휩싸였다.
그렇다. 서버 컴포넌트가 렌더링한 결과물은 순수한 HTML 덩어리일 뿐, 그 이상도 이하도 아니었다. 동적인 기능이 없으니, 클라이언트에서 자바스크립트로 무언가를 연결해 줄 필요가 전혀 없었다.
React는 이제 더 이상 무식하게 애플리케이션 전체를 하이드레이션할 필요가 없었다. 그저 트리 구조를 스캔하다가, 'use client'
지시어가 붙은 클라이언트 컴포넌트를 만났을 때만 멈춰서, 해당 부분에만 선택적으로 생명을 불어넣어 주면 그만이었다.
이것이 바로 ‘선택적 하이드레이션(Selective Hydration)’의 탄생이었다.
거대한 하나의 병목 지점은 사라졌다. 이제 페이지는 여러 개의 작은 섬으로 이루어진 군도와 같았다. 사용자가 ‘장바구니 담기’ 버튼 근처로 마우스를 가져가 클릭하면, React는 다른 부분을 기다리지 않고 즉시 그 버튼부터 하이드레이션하여 상호작용이 가능하게 만들 수 있었다. 페이지 하단에 있는 무거운 캐러셀(Carousel) 컴포넌트의 자바스크립트가 아직 로딩 중이라도 전혀 상관없었다.
‘전부 아니면 전무(All-or-Nothing)’의 저주는 풀렸다.
서버 컴포넌트는 단순히 번들 사이즈를 줄이는 기술이 아니었다. 그것은 하이드레이션이라는 과정을 잘게 쪼개고, 필요한 부분만 되살려냄으로써 ‘죽은 화면’의 악몽을 끝낼 수 있는 가장 강력한 무기였다. 사용자들은 이제 눈에 보이는 것을 즉시 만질 수 있게 될 터였다.