프론트엔드/Next.js

Next.js - 4가지 렌더링 방식 (SSG, SSR, CSR, ISR)

장쫑이이 2024. 9. 26. 13:00

 

 

SSG (Server Side Generation)

서버에서 미리 HTML 파일을 만든 다음 브라우저에서 보여주는 형태의 렌더링 방식

 

`빌드 타임`에 홈페이지를 만들어줌 > `정적 페이지`라서 초기에 한번 페이지를 로드하고 나서는 다시 로드하지 않음

vsCode 상 내용을 바꾸게 되면 다시 빌드를 해줘야함

 

실행과정

- 아무것도 하지 않아도 됨!! (Next.js는 기본적으로 아무것도 설정하지 않는다면 SSG로 동작)

 

yarn build && yarn start

빌드, 실행을 하면 아래와 같이 터미널에 뜸

 

(Static) 이라고 적힌걸 보면 0/ 으로 되어있는 곳이 정적인 페이지로 만들어졌다는 이야기이다.

 

 

서버 컴포넌트에서는 데이터를 불러올 때 useEffect등을 이용하지 않아도 됨

비동기 함수를 직접 사용할 수 있음!!

Next.js에서는 Fetch API를 통해서 최적화를 하고 있음 (Axios 사용 보다는 Fetch API사용하기!!)

 

export default async function Home() {
  const res = await fetch("http://localhost:4000/products");
  const data: Product[] = await res.json();

  return (
    <>
      <div>
        <div className="p-8 m-4">
          {data.map((product) => (
            <div className="flex border p-4 gap-4 rounded-md" key={product.id}>
              <img
                className="rounded-smr"
                width={150}
                height={150}
                src={product.images}
                alt={product.title}
              />
              <div className="flex flex-col justify-between">
                <div>
                  <h2 className="text-xl font-bold">{product.title}</h2>
                  <p className="text-sm">{product.description}</p>
                  <p className="mt-4 text-2xl">{product.price.amount}$</p>
                </div>
              </div>
            </div>
          ))}
        </div>
      </div>
    </>
  );
}

export type Product = {
  id: number;
  handle: string;
  availableForSale: boolean;
  isNew: boolean;
  title: string;
  description: string;
  descriptionHtml: string;
  options: {
    name: string;
    values: string[];
  }[];
  price: {
    amount: string;
    currencyCode: string;
  };
  images: string;
  seo: {
    title: string;
    description: string;
  };
  tags: string[];
  rating: number;
};

 

 

 

 

SSR(Server-Side-rendering)

사용자가 웹사이트에 접속을 하려고 시도 할 때마다 새로 콘텐츠를 불러와서 보여주는 렌더링 방식

(유저가 요청 할 때 마다)

 

사용방법

fetch 부분에 옵션만 추가하면 됨

export default async function Home() {
  const res = await fetch("http://localhost:4000/products", {
    cache: "no-store",
  });
  const data: Product[] = await res.json();
  console.log("렌더링 완료");

  return (
    <>
      <div>
      
 ...
 
 }

 

추가를 하게 되면 빌드를 했을 때, `0/ Static`으로 되어있던게 `f/ Dynamic`으로 변경되어있음

새로고침을 할 때 마다 렌더링이 되고 있음

 

 

서버 사이드 제너레이션

간단하게 옵션을 `force-cache`로 변경해주면 됨 / 기본이기에 안적도 됨

  const res = await fetch("http://localhost:4000/products", {
    cache: "force-cache",
  });
  const data: Product[] = await res.json();
  console.log("렌더링 완료");

 

 

 

 

 

클라이언트 사이드 렌더링

`"use client"` 사용이 필수!!

_components 폴더에 컴포넌트를 만들고 나서 흔히 리액트에서 사용하던 식으로 사용하면 됨

// componenet > ProductList.tsx

import React, { useEffect, useState } from "react";
import { Product } from "../page";

const ProductList = () => {
  const [data, setData] = useState<Product[]>([]);

  const fetchData = async () => {
    const res = await fetch("http://localhost:4000/products");
    const data: Product[] = await res.json();

    return data;
  };

  useEffect(() => {
    console.log("렌더링");
    fetchData().then(setData);
  }, []);

  return (
    <div className="p-8 m-4">
      {data.map((product) => (
        <div className="flex border p-4 gap-4 rounded-md" key={product.id}>
          <img
            className="rounded-smr"
            width={150}
            height={150}
            src={product.images}
            alt={product.title}
          />
          <div className="flex flex-col justify-between">
            <div>
              <h2 className="text-xl font-bold">{product.title}</h2>
              <p className="text-sm">{product.description}</p>
              <p className="mt-4 text-2xl">{product.price.amount}$</p>
            </div>
          </div>
        </div>
      ))}
    </div>
  );
};

export default ProductList;
//page.tsx

export default async function Home() {
  return (
    <>
      <div>
        <ProductList />
      </div>
    </>
  );
}

서버가 아닌 클라이언트에서 console이 찍히는걸 볼 수 있음

 

 

 

 

ISR (Incremental Static Regeneration) - 정적 증분 방식

특정 타입에 맞춰서 특정 타임에만 렌더링 다시 되도록 하는 SSG와 SSR이 섞여있는 방식

 

fetch에 next 옵션을 추가

revalidate라는 키에 들어간 값은 초 단위로 들어감

  const fetchData = async () => {
    const res = await fetch("http://localhost:4000/products", {
      next: {
        revalidate: 3,
      },
    });
    const data: Product[] = await res.json();

    return data;
  };

 

 

 

fetch의 옵션값인 next, cache 이 두 설정값과 "use client" 이 세가지만 알면

원하는 데 적재적소로 사용 가능