본문 바로가기

Computer Programming/Next

Next.js - fetch를 이용한 SSG, ISR, SSR, CSR 구현 옵션

1. SSG

- 비동기 데이터 fetching

data / products.json에 데이터가 있다고 가정하고

[
  {
    "id": "1",
    "name": "청바지",
    "price": "10000"
  },
  {
    "id": "2",
    "name": "티셔츠",
    "price": "13000"
  },
 ...objects
]

 

api 폴더의 products.ts 모듈을 만들어 데이터를 가져온다.

 

import path from "path";
import { promises as fs } from "fs";

export type Product = {
  id: string;
  name: string;
  price: string;
};

export async function getProducts(): Promise<Product[]> {
  const filePath = path.join(process.cwd(), "data", "products.json"); //data json 파일의 경로
  const data = await fs.readFile(filePath, "utf-8");
  return JSON.parse(data); //비동기적으로 파싱해서 object를 리턴해줌
}

export function getProduct(id: string) {
  return "shirt";
}

 

 

데이터를 읽어오는 컴포넌트

//비동기 !
export default async function ProductsPage() {
  const products = await getProducts();
  return (
    <>
      <ul>
        {products.map((product, idx) => (
          <Link key={idx} href={`/products/${product.id}`}>
            <li>{product.name}</li>
          </Link>
        ))}
      </ul>
    </>
  );
}

 

아이템 컴포넌트 에서 params를 읽어온 후 아이템을 가져오는 getProduct함수 호출

 

type Props = {
  params: {
    post: string;
  };
};

export function generateMetadata({ params }: Props) {
  return {
    title: `제품 이름 : ${params.post}`,
  };
}

//SSR
export default async function PostPage({ params: { post } }: Props) {
  const product = await getProduct(post);
  if (!product) {
    notFound();
  }
  return <h1>{product.name} 설명 페이지</h1>;
}


export async function generateStaticParams() {
  const products = await getProducts(); //await으로 promise가 끝날때 까지 기다린 후 값을 할당
  return products.map(({ id }) => ({
    post: id, //[post]에 대응되는 페이지는 id로 라우팅되고 있음
  }));
}

 

 

 

2. ISR

1) revalidate 코드 추가

export const revalidate = 3; //3초마다 revalidate

예를 들어 3초마다 변경하길 원하면 해당 컴포넌트들에 위의 코드를 추가해주면된다.

build 하고 start한 뒤, 코드를 변경해보면 리렌더링 후 3초 뒤 변경되는것을 볼 수 있다.

 

2) fetch의 두번째 인자 next options

export default async function ProductsPage() {
  const products = await getProducts();
  const res = await fetch("https://meowfacts.herokuapp.com", {
    next: { revalidate: 3 }, //3초마다 반영해서 ISR로 만들어줌
  });
  const data = await res.json();
  const fact = data.data[0];
  return (
    <>
      <h1>제품 소개 페이지!</h1>
      <ul>
        {products.map((product, idx) => (
          <Link key={idx} href={`/products/${product.id}`}>
            <li>{product.name}</li>
          </Link>
        ))}
      </ul>
      <article>{fact}</article>
    </>
  );
}

 

 

3. SSR

 

1) fetch의 두번째 인자 next options

 

0을 주면 SSR로 만들어 변화가 생기면 바로 반영해준다. (새로고침할 때 마다 반영됨)

 

...
export default async function ProductsPage() {
  const products = await getProducts();
  const res = await fetch("https://meowfacts.herokuapp.com", {
    // next: { revalidate: 3 }, //3초마다 반영해서 ISR로 만들어줌
    next: { revalidate: 0 }, // SSR로 만들어줌!
  });
...

SSR로 만들어준다 = 새롭게 html을 만들어준다

 

 

2) fetch의 두번째 인자 cache options

 

cache: "no-store"도 server side rendering처럼 동작한다. cache를 하지 않기 때문에 서버에서 변경되면 그때마다 html을 새로 생성한다.

...
export default async function ProductsPage() {
  const products = await getProducts();
  const res = await fetch("https://meowfacts.herokuapp.com", {
    // next: { revalidate: 3 }, //3초마다 반영해서 ISR로 만들어줌
    // next: { revalidate: 0 }, // SSR로 만들어줌!
    cache: "no-store",
  });
  
...

 

 

4. CSR

동적으로 자주 바뀌지만 페이지에서 중요하지는 않은 내용 -> CSR

혹은 구글맵 AP처럼 동적으로 자주 바뀌는 실시간 데이터일 경우 -> CSR

 

사용자가 화면에서 지도를 드래그하거나 줌을 조정하는 등의 인터랙션은 클라이언트 사이드에서 처리하는 것이 사용자 경험에 더 좋음

 

 

"use client";

import { useEffect, useState } from "react";

export default function MeowArticle() {
  const [text, setText] = useState();

  useEffect(() => {
    const fetchCats = async () => {
      const res = await fetch("https://meowfacts.herokuapp.com");
      const data = await res.json();
      setText(data.data[0]);
    };
    fetchCats();
  }, []);

  return <div>{text}</div>;
}

 

 

use client로 만들었더니 html에서 사라졌다...!!! 와우 정적인 요소가 지금 없기 때뮨....

 

 

 

정적인 요소를 채워넣고싶다면 

 

 

const [text, setText] = useState("데이터 준비중!");

 

데이터 준비중! 텍스트를 디폴트로 추가해보쟈... 그리고 다시 빌드하면

 

 

데이터 준비중! 이라는 정적인 데이터를 볼 수 있다. hydration 전까지 이 텍스트가 보이다가 hydration이 완료되면 cat article로 바뀐다. 짱신기