본문으로 건너뛰기
개발 머꼬
개발 노트Nuxt.js
hohyeon.dev22

페이지 이동이 데이터 로딩 때문에 멈춰 보이던 것을 고친 방법

  • #Engineering Note
  • #Nuxt.js
  • #Performance

문제 발생

목록에서 상세로 이동할 때, 클릭 후 아무 반응 없이 멈춰 있다가 화면이 한 번에 바뀌었습니다. 상세 페이지가 느린 API를 기다리는 동안 이전 화면에 그대로 있었기 때문입니다.

<script setup>
const { data: post } = await useFetch(`/api/posts/${slug}`);
</script>

원인 분석

useFetch는 내비게이션을 막습니다. 데이터가 준비된 뒤에 새 페이지를 보여주므로, 느린 요청은 곧 "먹통처럼 보이는 시간"이 됩니다.

Nuxt는 반대 동작을 하는 컴포저블을 제공합니다. 문서 설명대로 useLazyFetchlazy 옵션을 true로 설정해 핸들러가 해결되기 전에 내비게이션을 트리거하고, 데이터는 백그라운드에서 가져오는 동안 내비게이션이 즉시 진행되게 합니다.

대신 감수해야 할 것이 있습니다 — 문서가 경고합니다 — useLazyFetchawait 하더라도 데이터를 기다리지 않으므로, 결과가 처음에는 null일 수 있고 내용에 즉시 접근할 수 없습니다.

즉 이 컴포저블은 "빨라지는" 것이 아니라 기다리는 주체를 라우터에서 화면으로 옮기는 선택입니다. 그 화면을 우리가 만들어야 합니다.

해결 방안

  1. 템플릿에서 상태를 처리합니다. 문서가 안내하는 그대로 status를 확인합니다.
<script setup>
const { data: post, status } = await useLazyFetch(`/api/posts/${slug}`);
</script>

<template>
  <ArticleSkeleton v-if="status === 'pending'" />
  <ErrorState v-else-if="status === 'error'" />
  <Article v-else :post="post" />
</template>
  1. 스켈레톤을 실제 레이아웃에 맞춥니다. 모양이 다르면 데이터가 도착하는 순간 레이아웃이 튑니다 — 기다림을 줄이려다 다른 불편을 만듭니다.

  2. SEO가 중요한 페이지에는 쓰지 않습니다. 초기 HTML에 본문이 없으면 검색 유입에 불리합니다. 목록·상세처럼 색인이 필요한 화면은 useFetch로 서버에서 채웁니다.

  3. null 접근을 타입으로 막습니다. post?.title을 습관적으로 쓰기보다, 상태 분기 안에서만 post를 쓰도록 컴포넌트를 나누면 실수가 줄어듭니다.

  4. 변화에 반응해야 하면 watcher를 씁니다. 문서가 언급하듯 데이터는 null로 시작해 완료 시 반응형으로 채워지므로, 도착 시점에 할 일이 있으면 watch로 붙입니다.

  5. 정말 느린 API를 먼저 봅니다. 로딩 UI는 체감을 개선할 뿐입니다. 300ms로 줄일 수 있는 요청이라면 그쪽이 먼저입니다.

공식 문서

마지막 수정

좋아요북마크

댓글0

아직 댓글이 없어요. 첫 의견을 편하게 남겨 보세요.