사용자는 히어로를 안 본다: 라우팅·로딩·레이아웃으로 체감 속도 잡는 법

사용자는 히어로를 안 본다: 라우팅·로딩·레이아웃으로 체감 속도 잡는 법

React Router v7의 View Transition과 Lazy Route Discovery, 로드 타임 60% 단축 사례, 그리고 '카테고리가 진짜 액션 섹션'이라는 UX 인사이트를 엮어, 프론트엔드 체감 성능의 세 축을 해부합니다.

React Router v7 View Transition API Lazy Route Discovery 체감 성능 프론트엔드 최적화 UX 레이아웃 로딩 전략 Core Web Vitals
광고

솔직히 고백하면, 저도 히어로 섹션에 공들이는 타입이었습니다. 그래디언트 텍스트에 마이크로 인터랙션 넣고, Lottie 애니메이션 최적화하느라 새벽 3시까지 Figma 핀칭하고 있었죠. 그런데 최근 세 가지 소스를 교차해서 읽다 보니, 꽤 불편한 진실과 마주했습니다. 사용자는 히어로를 '보기만' 하고, 실제로 '행동'하는 곳은 완전히 다른 섹션이라는 것. 그리고 그 행동이 일어나는 순간의 체감 속도를 결정하는 건 라우팅, 로딩, 레이아웃—이 세 축의 설계였습니다.

라우팅: 사용자가 클릭하기 '전'에 준비를 끝내라

React Router v7의 API 변화를 정리한 velog 아티클을 보면, 눈에 띄는 키워드가 두 개 있습니다. Lazy Route DiscoveryView Transition API. 사실 이 두 기능의 본질은 같아요. "사용자가 이동을 느끼기 전에 이동을 끝내라." Lazy Route Discovery는 앱의 모든 경로 메타데이터를 초기 번들에 때려 넣지 않고, 현재 화면에 보이는 <Link><NavLink>를 감지해서 해당 라우트 정보만 선제적으로 요청합니다. 여기에 prefetch="intent" 옵션을 걸면, 사용자가 hover하는 순간 데이터와 모듈을 미리 땡겨 옵니다.

사용자 입장에서는 "클릭했더니 바로 뜬다"가 전부예요. 하지만 그 '바로'를 만들기 위해 라우터가 뒤에서 해주는 일이 꽤 정교합니다. View Transition API도 마찬가지인데, viewTransition prop 하나로 페이지 전환에 브라우저 네이티브 애니메이션을 입힐 수 있게 되면서, 기존에 Framer Motion이나 react-transition-group으로 직접 구현하던 전환 인터랙션의 번들 비용이 사라집니다. 이 라이브러리 도입하면 bundle size가 15~30KB는 늘어나는데, 브라우저 네이티브로 해결되면 그만큼 LCP가 깨끗해지는 거죠.

한 가지 더. <Form> 컴포넌트의 Progressive Enhancement 설계가 인상적입니다. JavaScript 로드 전에는 기본 HTML form으로 동작하고, 로드 후에는 fetch 기반 제출+자동 revalidation으로 업그레이드됩니다. 이건 Core Web Vitals의 INP(Interaction to Next Paint)를 직접 깎는 설계예요. "JS가 다 로드될 때까지 폼이 안 먹는" 그 찝찝한 순간을 없앤다는 뜻이니까요.

로딩: 5초를 2초로 만든 건 '한 방'이 아니라 '다섯 겹'

dev.to에 올라온 로드 타임 60% 단축 사례를 보면, 프론트엔드 개발자로서 좀 뜨끔합니다. 대시보드 로딩이 5초 걸렸는데, 원인 분석 결과 백엔드 N+1 쿼리(35% 개선), 과도한 페이로드(10~15%), 중복 API 호출, 캐싱 부재, 그리고 프론트엔드 렌더링까지 다섯 겹이 겹쳐 있었습니다. 프론트에서 한 일은 lazy loading, conditional rendering, 로딩 플레이스홀더 세 가지인데—이게 실제 백엔드 속도를 바꾸진 않지만 perceived performance, 즉 사용자가 느끼는 속도를 결정적으로 바꿉니다.

여기서 React Router v7의 <Await> 컴포넌트와 정확히 맞물립니다. React.Suspense 안에서 <Await resolve={reviews}>를 감싸면, Promise가 resolve되기 전까지 <ReviewsSkeleton />을 보여주고, 데이터가 오면 자연스럽게 교체됩니다. 스켈레톤 UI가 단순 디자인 장식이 아니라, 라우팅 레벨에서 비동기 데이터 흐름을 선언적으로 처리하는 구조가 되는 거예요. "여기서 로딩 스켈레톤 넣으면 어떨까요?"가 아니라, "여기서 <Await>로 데이터 경계를 선언하세요"가 정답인 시대입니다.

레이아웃: 카테고리가 '액션 섹션'이라는 불편한 사실

AllInOneTools 운영자가 공유한 UX 인사이트가 가장 뼈를 때립니다. 히어로 섹션은 시선을 끌지만, 실제 사용(usage)은 카테고리 섹션에서 시작된다. 사용자는 소개 텍스트를 거의 읽지 않고 스크롤해서 "내 도구가 어디 있지?"를 시각적으로 탐색합니다. 설명이 아니라 위치를 원하고, 이해가 아니라 확인을 원하고, 정보가 아니라 행동을 원합니다.

프론트엔드 관점에서 이걸 번역하면 이렇습니다. 사용자가 실제로 인터랙션하는 섹션이 뷰포트에 들어오는 순간이 진짜 '퍼스트 인터랙션'이고, 그 순간의 반응 속도가 체감 성능의 전부다. 히어로에 아무리 멋진 애니메이션을 넣어도, 카테고리 섹션까지 스크롤했을 때 해당 영역의 컴포넌트가 아직 하이드레이션되지 않았거나, 클릭했는데 라우트 정보를 그제야 불러오기 시작하면—사용자는 떠납니다. prefetch="viewport"가 왜 존재하는지, <Link> 컴포넌트가 화면에 보이는 순간 프리패치하는 옵션이 왜 필요한지, 이 맥락에서 완벽하게 설명됩니다.

카테고리 네이밍의 "명확성이 창의성을 이긴다(Clarity beats creativity)"는 원칙도 프론트엔드 구현으로 이어집니다. 카테고리 내부에 실제 도구 목록을 보여줬더니 engagement가 올라갔다는 건, 접힌 상태의 아코디언보다 펼쳐진 그리드가 낫다는 뜻이에요. CSS Grid의 auto-fillminmax()로 반응형 카테고리 카드를 깔고, 각 카드 안에 하위 도구를 미리 렌더링하되 content-visibility: auto로 뷰포트 밖의 페인팅 비용을 절약하는 게 실전 전략입니다.

시사점: 세 축을 하나의 흐름으로 연결하라

정리하면, 라우팅은 '다음 화면을 미리 준비'하고, 로딩은 '기다림을 구조적으로 선언'하고, 레이아웃은 '행동이 일어나는 지점에 자원을 집중'해야 합니다. React Router v7이 Lazy Route Discovery로 초기 번들을 깎고, <Await>+Suspense로 비동기 경계를 선언하고, View Transition으로 전환 비용을 브라우저에 위임하는 건—이 세 가지가 별개의 기능이 아니라 하나의 체감 성능 파이프라인이라는 설계 철학을 보여줍니다.

프론트엔드 개발자로서 제가 바꾸려는 습관은 이겁니다. Lighthouse 점수를 올리는 것과 사용자 체감 속도를 올리는 건 같은 일이 아닙니다. LCP가 아무리 빨라도, 사용자가 실제로 클릭하는 카테고리 섹션의 INP가 느리면 체감은 '느린 사이트'입니다. 히트맵 데이터가 말해주는 '진짜 액션 섹션'을 찾고, 그 섹션을 중심으로 프리패치 전략과 렌더링 우선순위를 재설계하는 것. 결국 사용자는 히어로를 안 봅니다. 사용자가 보는 곳에서 빨라야, 빠른 겁니다.

출처

더 많은 AI 트렌드를 Seedora 앱에서 확인하세요