위와 같은 페이지에 리스트 데이터가 렌더링 되기 전까지 스켈레톤을 보여주려고 한다. Next.js에서도 React와 마찬가지로 Suspense를 사용하여 Skeleton UI를 적용할 수 있다.
Skeleton 컴포넌트 구현하기
(app/components/Skeleton.tsx)
import styles from '@/styles/skeleton.module.scss'
interface SkeletonProps {
w: number
h: number
radius?: number
wUnit?: string
style?: React.CSSProperties
}
export default function Skeleton({
w,
h,
wUnit = 'px',
radius = 8,
style,
}: SkeletonProps) {
const size: React.CSSProperties = {
width: `${w}${wUnit}`,
height: `${h}px`,
borderRadius: `${radius}px`,
}
return <div className={styles.container} style={{ ...size, ...style }} />
}
(app/styles/skeleton.module.scss)
@-webkit-keyframes skeleton-gradient {
0% {
background-color: rgba(165, 165, 165, 0.1);
}
50% {
background-color: rgba(165, 165, 165, 0.3);
}
100% {
background-color: rgba(165, 165, 165, 0.1);
}
}
@keyframes skeleton-gradient {
0% {
background-color: rgba(165, 165, 165, 0.1);
}
50% {
background-color: rgba(165, 165, 165, 0.3);
}
100% {
background-color: rgba(165, 165, 165, 0.1);
}
}
.container {
-webkit-animation: skeleton-gradient 1.8s infinite ease-in-out;
animation: skeleton-gradient 1.8s infinite ease-in-out;
}
목록 대신 보여줄 Skeleton 만들기
(app/list/ListSkeleton.tsx)
import Skeleton from '@/components/Skeleton'
import { v4 as uuidv4 } from 'uuid'
export default function ListSkeleton() {
return (
<div>
{Array.from({ length: 10 }).map(() => (
<div key={uuidv4()}>
<Skeleton w={150} h={210} />
<Skeleton w={150} h={20} radius={4} style={{ marginTop: '6px' }} />
<Skeleton w={150} h={24} radius={4} style={{ marginTop: '3px' }} />
</div>
))}
</div>
)
}
목록 페이지에 Skeleton 적용하기
(app/list/page.tsx)
import { Suspense } from 'react'
import ListSkeleton from '../ListSkeleton'
import BookList from './BookList'
export default async function Page() {
return (
<div>
<Suspense fallback={<ListSkeleton />}>
<BookList />
</Suspense>
</div>
)
}
(app/list/BookList.tsx)
import BookInfoCard from '@/components/BookInfoCard'
import { formatBooksInfo } from '../_utils/formatBookInfo'
import bookApi from '../services'
export default async function BookList() {
const { totalResults, item } = await bookApi.getList()
const books = formatBooksInfo(item)
return (
<div>
{books &&
books.map((book) => <BookInfoCard book={book} key={book.isbn} />)}
</div>
)
}
결과물!
흰 화면만 보여주다가 스켈레톤을 적용하니 한층 더 보기 좋아졌다!
'Develop > NextJS' 카테고리의 다른 글
[Next.js] SEO 최적화 & 구글/네이버에 사이트 등록하기 (0) | 2024.08.10 |
---|---|
[Next.js] 스크롤 최상단 이동 버튼 구현하기 (0) | 2024.08.05 |
[Next.js] 서버 & 클라이언트 컴포넌트에서 토큰 관리하기 (0) | 2024.07.24 |
[Next.js] Data fetching과 Caching Mechanism (0) | 2024.06.12 |
[Next.js] Next.js 작업물 Vercel로 배포하기 (0) | 2023.07.21 |