logo

JEONGGON

    블로그
github
mode
목 차
down-arrow

Next.js Suspense

2024.02.18.

post-thumbnail

Suspense

1. Suspense의 필요성

// app/(movies)/movies/[id]/page.tsx

export default async function MovieDetail({ params: { id } }: { params: { id: string } }) {
  const [movie, videos] = await Promise.all([getMovie(id), getVideos(id)]);
  return <h1>{movie.title}</h1>;
}
  • 위와 같이 Promise.all()을 사용할 경우, fetch가 끝나고 movie와 video 모두가 생성되어야 UI를 볼 수 있음
  • 동시에 처리하더라도 fetch 함수를 분리하여 먼저 처리가 끝난 요소는 화면에 먼저 출력되도록 최적화 할 수 있음 (기다릴 필요 없음)
  • streaming을 사용하여 만약 movie가 준비되면 getVideo 함수가 로딩 중이더라도 해당 데이터와 연결된 UI가 사용자에게 보내지도록 처리
  • Suspense 방법을 적용하는 것이 최선은 아니며, 많은 데이터 소스에서 fetch해야 할 상황에 따라서 선택하여 적용할 수 있음


2. Suspense 적용하기

2-1. fetch 분리하기

  • fetch를 처리하고 해당 결과를 리턴할 movie-videos.tsx, movie-info.tsx 파일 생성
  • 기존에 page.tsx 파일에 작성한 fetch 함수 가져오기
// components/movie-videos.tsx

import { API_URL } from "../app/(home)/page";

async function getVideos(id: string) {
  await new Promise((response) => setTimeout(response, 3000));
  const response = await fetch(`${API_URL}/${id}/videos`);
  return response.json();
}

export default async function MovieVideos({ id }: { id: string }) {
  const videos = await getVideos(id);
  return <h6>{JSON.stringify(videos)}</h6>
}
// components/movie-info.tsx

import { API_URL } from "../app/(home)/page";

async function getMovie(id: string) {
  await new Promise((response) => setTimeout(response, 5000));
  const response = await fetch(`${API_URL}/${id}`);
  return response.json();
}

export default async function MovieInfo({ id }: { id: string }) {
  const movie = await getMovie(id);
  return <h6>{JSON.stringify(movie)}</h6>
}

  • 해당 컴포넌트 page.tsx에서 출력
// app/(movies)/movies/[id]/page.tsx

import MovieVideos from "../../../../components/movie-videos";
import MovieInfo from "../../../../components/movie-info";
import { Suspense } from "react";


export default async function MovieDetail({ params: { id } }: { params: { id: string } }) {
  return <div>
    <Suspense fallback={<h1>Loading movie info</h1>}>
      <MovieInfo id={id} />
    </Suspense>
    <Suspense fallback={<h1>Loading movie videos</h1>}>
      <MovieVideos id={id} />
    </Suspense>
  </div>;
}
  • 각 컴포넌트에 필요한 id Props를 전달
  • react에서 제공하는 Suspense 컴포넌트를 사용하여 fetch 데이터를 반환하는 MovieInfo와 MovieVideos 컴포넌트를 각각 감싼다.
  • Suspense component에는 fallback이라는 Props이 있고, fallback이 컴포넌트가 await되는 동안 표시할 메시지를 render 할 수 있도록 해줌
  • 병렬적으로 2가지를 동시에 fetch하고 나머지를 기다리지 않아도 됨

Suspense를 통한 개별 fetch
Suspense를 통한 개별 fetch

nextjsframeworkreactloadingsuspense
profile

조정곤

주니어 프론트엔드 개발자

github
linkedin
instagram
email

< 이전글

Next.js 에러

다음글 >

TypeScript 오버로딩

Nextjs 포스트 (13)

down-arrow