본문 바로가기
노마드코더10주챌린지

NextJS - Data Fetching

by 반갑조? 2025. 4. 9.

#3.0 Introduction

-Movie API
https://nomad-movies.nomadcoders.workers.dev
-JSON Viewer (구글 확장 프로그램)
https://chromewebstore.google.com/detail/json-viewer/gbmdgpbipfallnflgajpaliibnhdgobh

 

React에서 하는것처럼 fetch를 해보고난 다음에 Next.js에서 하는 fetch로 해본다. 두개를 비교.


#3.1 Client Side

로딩 직접 구현, metadata 못씀, fetch로 렌더링 일어남 등 client에서 데이터를 가져올 때 어떻게 되는지를 되새겨본다.

'use client';
import { useEffect, useState } from 'react';

export default function Page() {
  const [isLoading, setIsLoading] = useState(true);
  const [movies, setMovies] = useState([]);
  const getMovies = async () => {
    const response = fetch('https://nomad-movies.nomadcoders.workers.dev/movies');
    const json = await (await response).json();
    setMovies(json);
  };
  useEffect(() => {
    getMovies();
    setIsLoading(false);
  }, []);
  return (
    <div>
      <div>{isLoading ? 'Loading...' : JSON.stringify(movies)}</div>
    </div>
  );
}

#3.2 Server Side

export const metadata = {
  title: 'Home',
};

const URL = 'https://nomad-movies.nomadcoders.workers.dev/movies';

async function getMovies() {
  await new Promise(resolve => setTimeout(resolve, 5000));
  const response = await fetch(URL);
  const json = await response.json();
  return json;
}

export default async function HomePage() {
  const movies = await getMovies();
  return <div>{JSON.stringify(movies)}</div>;
}

-fetch
Next.js는 기본 웹 fetch() API를 확장하여 서버의 각 요청이 자체 영구 캐싱 의미를 설정할 수 있도록 한다.

-Error Lens
VSCode에서 오류, 경고 및 기타 언어 진단을 강조하여 표시해주는 익스텐션이다.


#3.3 Loading Components

-Loading UI and Streaming
특수 파일 loading.js는 React Suspense를 사용하여 의미 있는 로딩 UI를 만드는 데 도움이 된다.
이 규칙을 사용하면 route 세그먼트의 콘텐츠가 로드되는 동안 서버에서 즉시 로딩 상태를 표시할 수 있다. 렌더링이 완료되면 새 콘텐츠가 자동으로 교체된다.
즉시 로딩 상태는 탐색 시 즉시 표시되는 대체 UI이다. 스켈레톤, 스피너 등 로딩 표시기나 표지 사진, 제목 등 미래 화면의 작지만 의미 있는 부분을 미리 렌더링할 수 있다.

 

이름은 반드시 loading이여야하고, page파일 옆에 위치해야만 한다.


#3.4 Parallel Requests

-Promise.all()
Promise.all()는 자바스크립트에서 여러 비동기 작업을 동시에 실행하고, 모든 작업이 완료될 때까지 기다렸다가 결과를 배열 형태로 반환하는 함수이다. 쉽게 말해, 여러 Promise를 모두 이행할 때까지 기다린 후, 그 결과를 한꺼번에 받아볼 수 있게 해준다.

Promise.all()은 하나라도 reject되면 전체가 reject되므로 오류 처리를 잘 해준다면 여러 Promise의 비동기 처리를 할 때 정말 유용하게 사용이 가능하다.

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

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

async function getVideos(id: string) {
  console.log(`Fetching videos: ${Date.now()}`);
  await new Promise(resolve => setTimeout(resolve, 5000));
  const response = await fetch(`${API_URL}/${id}/videos`);
  return response.json();
}

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>;
}

병렬적으로 fetch하는 방법 중 하나이다. 다른 방법 중 하나는 다음에 배우는 suspense이다.


#3.5 Suspense

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

export default async function MovieDetail({ params: { id } }: { params: { id: string } }) {
 return (
    <div>
      <h3>Movie detail page</h3>
      <Suspense fallback={<h1>Loading movie info</h1>}>
        <MovieInfo id={id} />
      </Suspense>
      <Suspense fallback={<h1>Loading movie videos</h1>}>
        <MovieVideos id={id} />
      </Suspense>
    </div>
  );
}

 

-nextjs15부터는 기본 캐싱이 안된다. 옵션을 넣어 줘야 캐싱이 된다.

방법1. next.config.ts파일 추가

const nextConfig = {
experimental: {
staleTimes: {
dynamic: 30,
},
},
};

module.exports = nextConfig;

 

방법2. typescript 5.1.3버전 이상, @types/react 18.2.8버전 이상 설치. @types/react가 없으므로 npm i-D @types/react 로 설치하기.

 

방법3. 컴포넌트 위에 주석 {/* @ts-expect-error Async Server Component */} 추가하기

{/* @ts-expect-error Async Server Component */}
< MovieInfo id={id} / >
{/* @ts-expect-error Async Server Component */}
< MovieVideos id={id} / >

 

캐싱을 확인하려면 fetch의 두 번째 인자의 cache옵션을 'force-cache'로 바꿔줘야한다.

const response = await fetch(`${API_URL}/${movieId}`, {
cache: "force-cache",
});

 

 

Page 단위 로딩 => loading.tsx
서버 컴포넌트 단위 로딩 => Suspense


#3.6 Recap


#3.7 Error Handling

-error.js
error 파일을 사용하면 예기치 않은 런타임 오류를 처리하고 대체 UI를 표시할 수 있다.
error.js는 React Error Boundary에서 라우트 세그먼트와 중첩된 자식을 래핑한다.
바운더리 내에서 오류가 발생하면 오류 컴포넌트가 대체 UI로 표시된다.

-Global Error
global-error.js를 사용하여 루트 레이아웃이나 템플릿의 오류를 처리할 수 있다.

 

-Error Handling


-ErrorBoundary


#3.8 Conclusions

'노마드코더10주챌린지' 카테고리의 다른 글

NextJS - Deployment  (0) 2025.04.14
6주차 주간회고(4/5~4/11)  (0) 2025.04.11
NextJS - Routing  (0) 2025.04.09
Next.js 시작하기(Node.js 버전 업그레이드)  (0) 2025.04.08
5주차 주간회고(3/29~4/4)  (0) 2025.04.04