Front-end/Next.js

[Next.js] Next.js 에서 데이터 가져오기 - getInitialProps, getStaticProps, getStaticPaths, getServerSideProps

영벨롭 2024. 7. 10. 19:54

📌 Next.js 가 SSR 을 수행하는 방식

SSR(Server Side Rendering)서버 측에서 렌더링 준비가 완료된 완성된 HTML 문서를 클라이언트에게 전달하는 렌더링 방식입니다. 

 

처음 렌더링이 될 때, 서버 측에서 데이터도 함께 가져와서 그려주기 때문에 초기 로딩속도가 빠릅니다.

하지만, 페이지를 넘길 때마다 서버 측에서 다시 불러와야하기 때문에 CSR(Client Side Rendering)보다 서버 부하가 많습니다.

 

그럼에도 SSR을 사용하는 이유는 페이지가 로딩될 때 데이터도 동시에 로드되기 때문에 SEO에 유리하기 때문입니다.

 

Next.js는 SSR을 기반으로 하지만, 페이지가 로드된 이후엔 React에서 CSR을 이용하는 방식을 차용합니다.

  • 서버가 페이지를 그려줍니다. pages/ 폴더를 기반으로 해당 페이지들을 서버 측에서 먼저 로드해줍니다.
  • 페이지가 그려진 이후에는 페이지 내부에서 동적인 데이터를 패칭하는 과정(fetch, axios 등)은 CSR의 방식을 따릅니다.
    • 이때의 데이터들은 페이지가 로드된 이후 클라이언트 측에서 다시 렌더링해야하기 때문에, SEO는 걸리지 않습니다.

 

따라서 페이지기 로드될 때 함께 데이터가 패칭되어야 하는 상황(Pre-rendering)이라면,

Next.js의 getInitialProps, getstaticProps, getStaticPaths, getServerSideProps 메소드를 이용하여 페이지와 함께 데이터가 패칭될 수 있도록 처리해주어야 합니다.

 

데이터 패칭 메소드들리턴 값을 해당 컴포넌트의 props로 보내게 됩니다. 

 

 

✅ Next.js 의 데이터 가져오기 및 렌더링 과정

  1. 서버에서 요청한 페이지 찾기
    1. 클라이언트가 특정 URL을 요청하면, Next.js 서버는 해당 URL에 맞는 Page Component를 찾습니다.
  2. _app.tsx 의 getInitialProps 실행
    1. _app.tsx 파일에 getInitialProps 메서드가 정의되어 있다면, 실행합니다.
    2. 이 메서드는 서버와 클라이언트 모두에서 실행될 수 있으며, Page Component의 초기 데이터를 가져오거나 설정합니다.
  3. Page Component 의 getInitialProps 실행
    1. 요청된 Page Component 에 getInitialProps 메서드가 정의되어 있다면, 실행합니다.
    2. 이 때, 필요한 데이터를 불러와 props 로 받아오게 됩니다.
  4. 모든 props 구성 및 렌더링
    1. _app.tsx 에서 받아온 Page Component 의 props 와 해당 페이지에서 받아온 pageProps 를 합쳐서 최종적인 props 를 구성합니다.
    2. 이후 Next.js 는 _app.tsx에서 Page Component 를 렌더링합니다.
  5. _document.tsx 의 getInitialProps 실행
    1. _document.tsx 파일은 페이지가 렌더링될 때의 공통 HTML 레이아웃을 정의합니다.
    2. getInitialProps 메서드가 있다면, 최종적인 HTML 을 생성하기 전에 실행합니다.
    3. 이 메서드에서 필요한 추가적인 데이터를 불러와 pageProps 를 받아오게 됩니다.
  6. 모든 content 구성 및 HTML 출력
    1. _document.tsx 에서 최종적으로 구성된 HTML 을 사용하여 전체 페이지의 HTML 을 생성합니다.
    2. 이 HTML 은 서버에서 클라이언트로 전송되어 사용자에게 보여집니다.

📌 getInitialProps

getInitialProps 메서드는 Next.js 의 페이지나 컴포넌트에서 사용되는 메서드로,

데이터를 불러와 페이지의 초기 데이터를 설정할 수 있습니다.

 

getInitialProps 메서드를 호출하는 페이지나 컴포넌트의 Props 와 동일한 타입을 반환합니다. 

 

✅ 사용해야 하는 경우

  • 서버 사이드 렌더링(SSR)이 필요한 경우
  • 초기 렌더링 시 데이터가 필요한 경우
import { NextPage, NextPageContext } from "next";

import { useRouter } from "next/router";
import { PostType } from "../../../src/types/post";

type Props = {
  data?: PostType;
  isError?: boolean;
};

const PostPage: NextPage = ({ data, isError }: Props) => {
  const router = useRouter();
  const { id } = router.query;

  console.log(data);

  if (isError) return <>Error</>;

  return (
    <>
      <h2>Post Page id = {id}</h2>
      <h3>title: {data?.title}</h3>
      <p>{data?.body}</p>
    </>
  );
};

export default PostPage;

PostPage.getInitialProps = async (context: NextPageContext): Promise<Props> => {
  try {
    const url = "https://jsonplaceholder.typicode.com/posts/1";
    const res = await fetch(url, { method: "get" });
    const data = (await res.json()) as PostType;

    return { data };
  } catch {
    return { isError: true };
  }
};


📌 getStaticProps

getStaticProps 메서드는 Next.js에서 정적 생성(Static Generation)을 위해 사용되는 메서드입니다.

빌드 시에 미리 데이터를 불러와 HTML 로 변환하여 제공하므로, 요청 시 서버에서 동적으로 데이터를 생성하지 않습니다.

즉, 빌드시 고정되는 값으로 빌드 이후에는 데이터가 변하지 않습니다.

 

✅ getStaticProps 메서드의 반환 타입: GetStaticPropsResult<T>

  • props: 페이지 컴포넌트에 전달할 정적 props 객체 (타입: T)
  • revalidate: 페이지의 재생성 간격을 지정하는 정수 또는 불리언 값
  • notFound: 페이지가 없음(404)를 나타내는 불리언 값

 

✅ 사용해야 하는 경우

  • SSG가 필요한 경우
  • 빌드 시점에 데이터를 불러와서 페이지에 필요한 초기 데이터를 설정할 경우
import {
  GetStaticPropsContext,
  GetStaticProps,
  GetStaticPropsResult,
  NextPage,
} from "next";

import { useRouter } from "next/router";
import { PostType } from "../../../src/types/post";

type Props = {
  data?: PostType;
  isError?: boolean;
};

const PostPage: NextPage = ({ data, isError }: Props) => {
  const router = useRouter();
  const { id } = router.query;

  console.log(data);

  if (isError) return <>Error</>;

  return (
    <>
      <h2>Post Page id = {id}</h2>
      <h3>title: {data?.title}</h3>
      <p>{data?.body}</p>
    </>
  );
};

export default PostPage;

export const getStaticProps: GetStaticProps = async (
  context: GetStaticPropsContext
): Promise<GetStaticPropsResult<Props>> => {
  const url = "https://jsonplaceholder.typicode.com/posts/1";

  try {
    const res = await fetch(url, {
      method: "get",
    });
    const data = (await res.json()) as PostType;

    return { props: { data } };
  } catch (err) {
    return { notFound: true };
  }
};

📌 getStaticPaths

getStaticPaths 메서드는 빌드 시점에 동적 경로를 생성할 때 사용됩니다.

동적으로 생성되는 페이지의 경로(ex. /post/[postId])를 미리 정의하고, 이에 해당하는 라우팅을 설정할 수 있습니다.

 

주로 동적 라우팅getStaticProps 를 함께 사용할 때 사용합니다.

여기서 정의하지 않은 하위 경로는 접근해도 화면에 뜨지 않으며, 동적라우팅 되는 경우의 수를 하나하나 집어넣어야 합니다.

 

✅ getStaticPaths 메서드의 반환 타입: GetStaticPathsResult<T>

  • paths: 문자열 배열 또는 { params: { [key: string]: string | string[] } } 객체의 배열입니다.
    • 동적 경로에서 생성할 모든 경로의 목록을 나타냅니다. 
  • fallback: paths 이외의 경로들(페이지가 없는 경우)의 대체 방법을 나타냅니다.
    • true: 요청된 경로가 없을 때 Next.js 는 동적으로 페이지를 생성합니다.
    • false: paths에 나열된 경로 외에는 404 페이지를 반환합니다.
    • 'blocking': 요청이 들어올 때까지 페이지 생성을 블록하며, 생성될때까지 대기합니다. 이는 SSR 시 사용됩니다.

 

✅ 사용해야 하는 경우

  • 빌드 시점에 동적 경로 생성이 필요한 경우
  • getStaticProps와 함께 사용하여 동적으로 생성되는 페이지를 정적으로 미리 빌드할 때 사용
import {
  GetStaticPaths,
  GetStaticPathsContext,
  GetStaticPathsResult,
  GetStaticProps,
  GetStaticPropsContext,
  GetStaticPropsResult,
  NextPage,
} from "next";

import { useRouter } from "next/router";
import { PostType } from "../../../src/types/post";

type Props = {
  data?: PostType;
  isError?: boolean;
};

const PostPage: NextPage = ({ data, isError }: Props) => {
  const router = useRouter();
  const { id } = router.query;

  console.log(data);

  if (isError) return <>Error</>;

  return (
    <>
      <h2>Post Page id = {id}</h2>
      <h3>title: {data?.title}</h3>
      <p>{data?.body}</p>
    </>
  );
};

export default PostPage;

// 빌드될 때 실행
export const getStaticPaths: GetStaticPaths = async (
  context: GetStaticPathsContext
): Promise<GetStaticPathsResult<{ id: string }>> => {
  // posts를 받기 위해 fetch
  const url = "https://jsonplaceholder.typicode.com/posts";
  const res = await fetch(url, { method: "get" });
  const posts = (await res.json()) as PostType[];

  // pre-render할 Path를 얻음 (posts를 통해서)
  const paths = posts.map((post) => ({
    params: { id: post.id },
  }));

  return { paths, fallback: false };
};

export const getStaticProps: GetStaticProps = async (
  context: GetStaticPropsContext
): Promise<GetStaticPropsResult<Props>> => {
  const { params } = context;
  const url = `https://jsonplaceholder.typicode.com/posts/${params?.id}`;

  try {
    const res = await fetch(url, {
      method: "get",
    });
    const data = (await res.json()) as PostType;

    return { props: { data } };
  } catch (err) {
    return { notFound: true };
  }
};

 


📌 getServerSideProps

getServerSideProps 메서드는 빌드와 상관없이, 매 페이지 요청마다 데이터를 서버로부터 가져옵니다. 

서버 사이드 렌더링(SSR)을 위해 사용되며, 최신 데이터를 제공하고 SEO에 유리한 방식입니다. 

 

✅ getServerSideProps 메서드의 반환 타입 : GetServerSidePropsResult<T>

  • props: 컴포넌트에 전달할 props 객체입니다. (타입: T)
  • notFound: 페이지가 없음(404)를 나타내는 불리언 값입니다.
  • redirect: 페이지를 다른 경로로 리디렉션할 수 있습니다.
    • destination: 리디렉션할 목적지 URL 입니다.
    • permanent: 옵션으로, true 일 경우 영구 리디렉션을 의미하며, 기본값은 false 입니다.
    • statusCode: 옵션으로, 클라이언트에 반환될 HTTP 상태 코드입니다. 기본값은 302입니다.

 

✅ 사용해야 하는 경우

  • 서버 사이드 렌더링(SSR)이 필요한 경우
  • 요청 시에 매번 최신 데이터를 제공해야 할 때 사용
import {
  GetServerSideProps,
  GetServerSidePropsContext,
  GetServerSidePropsResult,
  NextPage,
} from "next";

import { useRouter } from "next/router";
import { PostType } from "../../../src/types/post";

type Props = {
  data?: PostType;
  isError?: boolean;
};

const PostPage: NextPage = ({ data, isError }: Props) => {
  const router = useRouter();
  const { id } = router.query;

  console.log(data);

  if (isError) return <>Error</>;

  return (
    <>
      <h2>Post Page id = {id}</h2>
      <h3>title: {data?.title}</h3>
      <p>{data?.body}</p>
    </>
  );
};

export default PostPage;

export const getServerSideProps: GetServerSideProps = async (
  context: GetServerSidePropsContext
): Promise<GetServerSidePropsResult<Props>> => {
  const url = "https://jsonplaceholder.typicode.com/posts/1";

  try {
    const res = await fetch(url, { method: "get" });
    const data = (await res.json()) as PostType;

    return { props: { data } };
  } catch {
    return { notFound: true };
  }
};

📌 정리

  • getInitialProps
    • SSR 에서 사용됩니다.
    • 페이지 컴포넌트의 초기 데이터를 fetching 할 때 사용됩니다.
  • getStaticProps
    • SSG 에서 사용되는 페이지 컴포넌트의 정적 메소드입니다. 
    • 페이지가 빌드 시에 한 번 호출되어 초기 데이터를 가져옵니다. 
    • export 해주어야 Next.js 가 이를 인식하여 빌드 시 호출합니다.
  • getStaticPaths
    • SSG 에서 사용되는 동적 라우팅을 지원하는 메소드입니다.
    • getStaticProps와 함께 사용되며, 모든 가능한 동적 경로의 리스트를 정의해야 합니다. 
    • 각 경로에 대해 미리 데이터를 불러와서 정적 페이지를 생성합니다.
    • export 해주어야 Next.js 가 이를 인식하여 빌드 시 호출합니다.
  • getServerSideProps
    • SSR 에서 사용되는 페이지 컴포넌트의 정적 메소드입니다.
    • 각 페이지 요청마다 서버에서 실행되어 데이터를 불러옵니다.
    • 매 요청마다 최신 데이터를 제공하며, SEO 에 유리합니다.
    • export 해주어야 Next.js 가 이를 인식하여 요청 시 호출합니다.

 

 

 

 

 

 

 

 

 

 

 

 

 

 

반응형