로딩 UI 구현하기
Next.js의 로딩 UI 기능은 사용자 경험을 크게 향상시킬 수 있는 강력한 도구입니다.
이 절에서는 로딩 UI의 구현 방법과 Suspense 경계 사용에 대해 자세히 알아보겠습니다.
loading.js 파일의 역할과 사용 방법
loading.js
파일은 Next.js에서 자동으로 Suspense 경계를 생성하는 특별한 파일입니다.
이 파일은 해당 라우트 세그먼트와 그 하위 요소들이 로딩 중일 때 표시될 UI를 정의합니다.
기본 사용 예시
export default function DashboardLoading() {
return <div>Loading dashboard...</div>
}
이 파일은 /dashboard
경로와 그 하위 경로에 대한 로딩 UI를 제공합니다.
스트리밍과 서스펜스의 개념
스트리밍은 서버에서 UI를 점진적으로 렌더링하고 전송하는 기술입니다.
Suspense는 React의 기능으로, 컴포넌트의 렌더링을 특정 조건이 충족될 때까지 지연시킬 수 있게 해줍니다.
Next.js는 이 두 개념을 결합하여, 페이지의 일부분이 준비되는 대로 점진적으로 표시할 수 있게 합니다.
로딩 상태를 세밀하게 제어하는 방법
더 세밀한 로딩 제어를 위해 React의 Suspense
컴포넌트를 직접 사용할 수 있습니다.
import { Suspense } from 'react'
import Loading from './loading'
export default function Dashboard() {
return (
<div>
<h1>Dashboard</h1>
<Suspense fallback={<Loading />}>
<DashboardContent />
</Suspense>
</div>
)
}
이 방식을 사용하면 페이지의 특정 부분에 대해서만 로딩 UI를 적용할 수 있습니다.
고급 로딩 전략
- 지연된 로딩 : 매우 짧은 로딩에 대해 로딩 UI를 표시하지 않도록 할 수 있습니다.
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
}
- 중첩된 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를 구현해보세요.
- 전체 페이지 레이아웃을 유지하는 skeleton UI 생성
- 헤더, 사이드바, 메인 컨텐츠 영역에 대한 개별 skeleton 컴포넌트 구현
- 중첩된 Suspense를 사용하여 각 영역을 독립적으로 로드
- 로딩 시간이 일정 시간(예 : 300ms)을 넘길 때만 skeleton UI 표시
구현 예시
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>
)
}
'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와 지연된 로딩 기법을 활용하여 더 나은 사용자 경험을 제공하는 방법을 익힐 수 있습니다.
이는 대규모 애플리케이션에서 로딩 상태를 효과적으로 관리하는 데 필요한 고급 기술입니다.