icon안동민 개발노트

로딩 UI 구현하기


 Next.js의 로딩 UI 기능은 사용자 경험을 크게 향상시킬 수 있는 강력한 도구입니다.

 이 절에서는 로딩 UI의 구현 방법과 Suspense 경계 사용에 대해 자세히 알아보겠습니다.

loading.js 파일의 역할과 사용 방법

 loading.js 파일은 Next.js에서 자동으로 Suspense 경계를 생성하는 특별한 파일입니다.

 이 파일은 해당 라우트 세그먼트와 그 하위 요소들이 로딩 중일 때 표시될 UI를 정의합니다.

 기본 사용 예시

app/dashboard/loading.js
export default function DashboardLoading() {
  return <div>Loading dashboard...</div>
}

 이 파일은 /dashboard 경로와 그 하위 경로에 대한 로딩 UI를 제공합니다.

스트리밍과 서스펜스의 개념

 스트리밍은 서버에서 UI를 점진적으로 렌더링하고 전송하는 기술입니다.

 Suspense는 React의 기능으로, 컴포넌트의 렌더링을 특정 조건이 충족될 때까지 지연시킬 수 있게 해줍니다.

 Next.js는 이 두 개념을 결합하여, 페이지의 일부분이 준비되는 대로 점진적으로 표시할 수 있게 합니다.

로딩 상태를 세밀하게 제어하는 방법

 더 세밀한 로딩 제어를 위해 React의 Suspense 컴포넌트를 직접 사용할 수 있습니다.

app/dashboard/page.js
import { Suspense } from 'react'
import Loading from './loading'
 
export default function Dashboard() {
  return (
    <div>
      <h1>Dashboard</h1>
      <Suspense fallback={<Loading />}>
        <DashboardContent />
      </Suspense>
    </div>
  )
}

 이 방식을 사용하면 페이지의 특정 부분에 대해서만 로딩 UI를 적용할 수 있습니다.

고급 로딩 전략

  1. 지연된 로딩 : 매우 짧은 로딩에 대해 로딩 UI를 표시하지 않도록 할 수 있습니다.
app/dashboard/page.js
import { Suspense } from 'react'
 
export default function Dashboard() {
  return (
    <Suspense fallback={<DelayedLoading />}>
      <DashboardContent />
    </Suspense>
  )
}
 
function DelayedLoading() {
  return (
    <Suspense fallback={null}>
      <DelayWrapper>
        <LoadingUI />
      </DelayWrapper>
    </Suspense>
  )
}
 
function DelayWrapper({ children }) {
  useEffect(() => {
    const timer = setTimeout(() => setShowLoading(true), 500)
    return () => clearTimeout(timer)
  }, [])
 
  return showLoading ? children : null
}
  1. 중첩된 Suspense : 페이지의 다른 부분에 대해 다른 로딩 상태를 표시할 수 있습니다.
<Suspense fallback={<PageSkeleton />}>
  <Header />
  <Suspense fallback={<ContentSkeleton />}>
    <MainContent />
  </Suspense>
  <Suspense fallback={<SidebarSkeleton />}>
    <Sidebar />
  </Suspense>
</Suspense>

6장 데이터 페칭과의 연결

 5장의 로딩 UI 구현은 6장의 데이터 페칭과 밀접하게 연관됩니다.

 데이터를 비동기적으로 가져올 때, 로딩 UI를 사용하여 사용자에게 데이터가 로드 중임을 알려줄 수 있습니다.

 Next.js의 서버 컴포넌트와 함께 사용하면, 데이터가 준비되는 대로 UI를 점진적으로 스트리밍할 수 있습니다.

실습 : Skeleton UI 기반 로딩 상태 구현

 다음 요구사항을 만족하는 대시보드 페이지의 로딩 UI를 구현해보세요.

  1. 전체 페이지 레이아웃을 유지하는 skeleton UI 생성
  2. 헤더, 사이드바, 메인 컨텐츠 영역에 대한 개별 skeleton 컴포넌트 구현
  3. 중첩된 Suspense를 사용하여 각 영역을 독립적으로 로드
  4. 로딩 시간이 일정 시간(예 : 300ms)을 넘길 때만 skeleton UI 표시

 구현 예시

app/dashboard/page.js
import { Suspense } from 'react'
import SkeletonHeader from './SkeletonHeader'
import SkeletonSidebar from './SkeletonSidebar'
import SkeletonContent from './SkeletonContent'
import Header from './Header'
import Sidebar from './Sidebar'
import Content from './Content'
import DelayedFallback from './DelayedFallback'
 
export default function DashboardPage() {
  return (
    <div className="dashboard-layout">
      <Suspense fallback={<DelayedFallback><SkeletonHeader /></DelayedFallback>}>
        <Header />
      </Suspense>
      <div className="dashboard-body">
        <Suspense fallback={<DelayedFallback><SkeletonSidebar /></DelayedFallback>}>
          <Sidebar />
        </Suspense>
        <Suspense fallback={<DelayedFallback><SkeletonContent /></DelayedFallback>}>
          <Content />
        </Suspense>
      </div>
    </div>
  )
}
app/dashboard/DelayedFallback.js
'use client'
import { useState, useEffect } from 'react'
 
export default function DelayedFallback({ children }) {
  const [show, setShow] = useState(false)
 
  useEffect(() => {
    const timer = setTimeout(() => setShow(true), 300)
    return () => clearTimeout(timer)
  }, [])
 
  return show ? children : null
}

 이 실습을 통해 skeleton UI를 사용한 고급 로딩 상태를 구현하고, Suspense와 지연된 로딩 기법을 활용하여 더 나은 사용자 경험을 제공하는 방법을 익힐 수 있습니다.

 이는 대규모 애플리케이션에서 로딩 상태를 효과적으로 관리하는 데 필요한 고급 기술입니다.