JiSoo's Devlog

[Next.js] Data Fetching 본문

Frontend/Next.js

[Next.js] Data Fetching

지숭숭숭 2024. 10. 14. 16:35

client에서 모든 것을 fetch 하려면 보안을 위해 항상 API를 중간에 만들어 요청하고 API가 안전한 환경에 있다면 그 뒤에 데이터베이스에 요청을 보낸다

useState를 사용하면 metadata도 사용하지 못한다

 

 

Server Side

어떤 일이 발생하기를 기다리려고 await를 사용할 때 async를 무조건 써야 한다!

useEffect, useState를 쓰지 않아도 되고 로딩 상태를 구현하지 않아도 된다

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

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

async function getMovies() {
  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>;
}

Next.js는 프레임워크이기 때문에 server component를 사용한다면 fetch 된 url을 자동으로 캐싱시켜 준다

브라우저가 어떤 것도 fetch 하지 않는다

async function getMovies() {
  console.log("I'm fetching!");
  const response = await fetch(URL);
  const json = await response.json();
  return json;
}

이런 식으로 확인해 주면 여기서 콘솔은 백엔드에서만 실행된다

로딩상태도 존재

server component에서 Next JS가 내가 fetch 한 것을 기억한다

하지만 저 함수가 완료되기 전까지는 백엔드에서 렌더링 작업이 이루어지지 않아서 사용자는 아무것도 볼 수 없다

 

 

Loading Components

loading.tsx 파일은 React Suspense를 사용해 의미 있는 로딩 UI를 만들어 준다

브라우저가 첫 번째로 보내는 일부분은 layout이나 navigation이고 그다음에 loading component를 보낸다

브라우저는 로딩이 끝날 때까지 기다리다가 백엔드 작업(함수작업)이 완료되면 응답 결과를 보여준다

 

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

여기서 HomePage 컴포넌트가 async여야 하는 이유는 NextJS가 이 컴포넌트에서 await 해야 하기 때문

await가 끝나면 브라우저에게 마지막 HTML 부분 전달

 

 

Parallel Requests

export default async function MovieDetail({
  params: { id },
}: {
  params: { id: string };
}) {
  console.log('start fetching')
  const movie = await getMovie(id);
  const videos = await getVideos(id);
  console.log('end fetching')

  return <h1>{movie.title}</h1>;
}

↓ ↓ ↓ ↓ ↓

export default async function MovieDetail({
  params: { id },
}: {
  params: { id: string };
}) {
  console.log('start fetching')
  const [movie, video] =  await Promise.all([getMovie(id), getVideos(id)]);
  console.log('end fetching')

  return <h1>{movie.title}</h1>;
}

 

Promise.all 은 자바스크립트에서 여러 비동기 작업을 동시에 실행하고 모든 작업이 완료될 때까지 기다렸다가 결과를 배열 형태로 반환하는 함수

여러 Promise를 모두 이행할 때까지 기다린 후, 그 결과를 한꺼번에 받아볼 수 있게 한다

병렬적 fetch 가능!

 

 

Suspense

데이터 소스가 여러 개라면 Suspense를 사용해야 한다

이전 방식은 page 컴포넌트에서 2가지 모두 fetch

지금 방식은 개별 파일에서 2가지를 render 할 건데 개별적으로 기다릴 수 있다

Suspense 컴포넌트에는 fallback이라는 prop이 있고 이건 컴포넌트가 await 되는 동안 표시할 메시지를 render 할 수 있게 한다

return (
    <div>
      <Suspense fallback={<h1>Loading movie info</h1>}>
        {/* @ts-expect-error Async Server Component */}
        <MovieInfo id={id} />
      </Suspense>
      <Suspense fallback={<h1>Loading movie videos</h1>}>
        {/* @ts-expect-error Async Server Component */}
        <MovieVideos id={id} />
      </Suspense>
    </div>
  );

2가지를 동시에 fetch할 수 있는데 하나의 요청이 완료되면 다른 컴포넌트를 기다릴 필요 없이 즉시 컴포넌트가 render 된다

이전에는 페이지 전체가 로딩 상태였다면 지금은 구체적으로 페이지의 어느 부분이 로딩 상태여야 하는지 명시해 줄 수 있다

 

 

Error Handling

error.js 파일을 사용하면 중첩된 경로에서 예기치 않은 런타임 오류를 적절히 처리할 수 있다

error.js는 중첩된 하위 세그먼트 혹은 page.js 구성 요소를 래핑 하는 React Error Boundary를 자동 생성한다

error.js 파일에서 내보낸 리액트 컴포넌트가 fallback 컴포넌트로 사용된다

 

728x90

'Frontend > Next.js' 카테고리의 다른 글

[Next.js] Deployment  (3) 2024.10.15
[Next.js] Routing  (0) 2024.08.04
[Next.js] Introduction  (0) 2024.07.29