본문 바로가기
React/Next.js

[Next.js] SSR, SSG, ISR

by dev수니 2023. 12. 4.
반응형

SSR

SSR은 Server Side Rendering 의 약자로 서버에서 페이지를 렌더링해서 클라이언트에 전달해주는 방식이다.

Next.js 에서 SSG 와 ISR 와 구분되는 이유는 렌더링 되는 시점이다.

SSR는 사용자가 요청할 때 마다 페이지를 새롭게 렌더링한다. 따라서 Fetching 해야하는 데이터가 빈번할 때 사용된다.

 

Next.js 12 에서는 이를 getServerSideProps라는 이름의 함수를 통해 값을 SSRPage에 렌더링한 후 클라이언트에 전달한다.

export default function SSRPage({ dateTime }: SSRPageProps) {
  return (
    <main>
      <TimeSection dateTime={dateTime} />
    </main>
  );
}

export const getServerSideProps: GetServerSideProps = async () => {
  const res = await axios.get('https://worldtimeapi.org/api/ip');

  return {
    props: { dateTime: res.data.datetime },
  };
};

Next.js 13 에서는 fetch 메서드를 이용한다. fetch(URL, { cache: 'no-store' }); 두번째 인자로 {cache: 'no-store'} 옵션을 넣어주면 된다.


SSG

SSG는 Static Site Generation의 약자로 Next js에서 페이지를 생성할 때 기본으로 적용되는 설정이다. SSR과 다른 점은 클라이언트가 요청하는 시점이 아니라 빌드 시에 페이지를 미리 생성해놓는 것이다. 빌드하는 시점에 페이지가 미리 생성되기 때문에 fetching하는 데이터가 변경되더라도 다시 빌드하지 않는 이상 반영되지 않는다.

 

Next.js 12 에서는 이를 getStaticProps라는 이름의 함수를 통해 값을 SSRPage에 렌더링한 후 클라이언트에 전달한다.

export default function SSGPage({ dateTime }: SSGPageProps) {
  return (
    <main>
      <TimeSection dateTime={dateTime} />
    </main>
  );
}

export const getStaticProps: GetStaticProps = async () => {
  const res = await axios.get('https://worldtimeapi.org/api/ip');

  return {
    props: { dateTime: res.data.datetime },
  };
};

 

또한 여기서 우리는 SSG를 통해 동적 라우팅을 사용할 수 있다.

getStaticPaths 를 사용하면 렌더링하기 위해 필요한 경로를 설정할 수 있다.

아래와 같이 사용하면 getStaticPathspathsgetStaticProps 로 리턴한다.

export async function getStaticPaths() {
  return {
    paths: [
      { params: { ... } }
    ],
    fallback: ...
  };
}

 

아래예제를 보면 각 포스팅을 위해, /pages/posts/[id].js 에 동적 라우팅하고 있다.

function BlogPost({ post }) {
  return (
    <div>
      <h1> {post.title} </h1>
      <div> {post.content} </div>
    </div>
  )
}

export async function getStaticPaths() {
  const res = await fetch('http://.../posts')
  const posts = await res.json()
  
  const paths = posts.map((post) => ({
    params: { id: post.id },
  }))
  
  return { paths, fallback: false }

}

export async function getStaticProps({ params }) {
  const res = await fetch(`https://.../posts/${params.id}`)
  const post = await res.json()
  return {
    props: {
      post,
    }
  }
}

export default BlogPost

getStaticPaths 에서 /posts 에 저장된 모든 블로그 포스팅 데이터를 불러오고, id 값을 파라미터로 리턴한다.
그러면 getStaticProps 에서는 각 path의 params 값을 받아 id를 통해 블로그 포스트를 불러오고, 그 post를 props로 컴포넌트에 전달한다.

 

그리고 fallback 은 paths에서 리턴되지 않은 경로에 대해서 어떻게 처리할지를 정해준다.

  • false : 404 를 전달하겠다.
  • true : 404를 전달하지 않고, "fallback" 버전의 페이지를 첫 request에서 보여준 후, 페이지가 생성되고 나면 그 이후의 request부터는 생성된 페이지를 보여주겠다.
  • blocking : 서버 사이드 렌더링을 통해 HTML이 생성되기 까지 기다리겠다.

 

Next.js 13 에서는 fetch 메서드를 이용한다. fetch(URL, { cache: 'force-cache' }); 두번째 인자로 {cache: 'force-cache'} 옵션을 넣어주면 된다.

 


ISR

ISR은 Incremental Static Regeneration의 약자로 빌드 시점에 페이지를 렌더링한 후, 설정한 시간 마다 페이지를 렌더링한다. SSG에 포함되는 개념이라고 할 수 있다. SSG는 빌드 시에 페이지를 생성하기 때문에 fetching 하는 데이터가 변경되면 다시 빌드해야 하지만 ISR은 일정 시간마다 알아서 페이지를 업데이트 해준다.

 

Next.js 12 에서는 이를 getStaticProps라는 이름의 함수를 통해 fetching할 데이터를 객체 내의 props 라는 key 값으로 보내고, revalidate 의 key 값으로 Number를 리턴하면 해당 seconds 마다 페이지가 렌더링된다.

export default function ISR20Page({ dateTime }: ISR20PageProps) {
  return (
    <main>
      <TimeSection dateTime={dateTime} />
    </main>
  );
}

export const getStaticProps: GetStaticProps = async () => {
  const res = await axios.get('https://worldtimeapi.org/api/ip');

  return {
    props: { dateTime: res.data.datetime },
    revalidate: 20,
  };
};

Next.js 13 에서는 fetch 메서드를 이용한다. fetch(URL, { next: { revalidate: 10 } }); 두번째 인자로 { next: { revalidate: 10 } 옵션을 넣어주면 된다.


Next.js 13  에서의 fetch()

async function fetchData(params: { id: string }) {
  const res = await fetch(
    `https://jsonplaceholder.typicode.com/posts/${params.id}`,
    { cache: 'force-cache' }, // SSG(default)
    // { cache: 'no-store' }, // SSR
    // { next: { revalidate: 15 } }, // ISR
  );
  const data = await res.json();
  return data;
}

export default async function Page({
  params,
}: {
  params?: any;
  children?: React.ReactNode;
}) {
  const data = await fetchData(params);

  return (
    <div className="space-y-4">
      <h1 className="text-2xl font-medium text-gray-100">{data.title}</h1>
      <p className="font-medium text-gray-400">{data.body}</p>
    </div>
  );
}

 

반응형

댓글