가수면

SSR, SSG, ISR, CSR 방법 본문

React/Next.js

SSR, SSG, ISR, CSR 방법

니비앙 2023. 6. 6. 04:36

클라이언트 컴포넌트, 서버 컴포넌트 선택 기준

Next 13 이상의 버전에서는 기본적으로 컴포넌트가 서버 컴포넌트와 클라이언트 컴포넌트로 구분되는데, 그렇다고 서버 컴포넌트=SSR, 클라이언트 컴포넌트=CSR개념은 아니다.

 

서버 컴포넌트

SSR의 경우 동적 컨텐츠를 다루는데, 서버 컴포넌트의 경우 동적 상호작용하는 로직들을 전부 클라이언트 컴포넌트에 위임함으로써 클라이언트에 전송되는 자바스크립트의 양을 최소화하는 데 초점을 맞춘 컴포넌트다.

SSR의 특정 역할을 클라이언트 컴포넌트에 덜어주어 최적화시킨 형태다.

클라이언트 컴포넌트

마치 SSR처럼 서버에서 렌더링 된 HTML을 생성한 뒤 클라이언트에서 수화 과정을 거치게 된다. 이후 CSR처럼 클라이언트 사이드에서 동적 컨텐츠들을 처리한다. SSR + CSR 방식이 혼합된 컴포넌트며 코드 스플리팅이 자동으로 적용된다.

 

둘 다 최적화되어 있기에 단순 렌더링 방식만 바꾼다고 성능에 큰 차이는 없다.

애초에 동적인 부분은 전부 클라이언트 컴포넌트로 강요되기 때문에 자연스레 결정되지만, 그 외에는 목적에 맞게 컴포넌트를 선택하면 된다.

SSG 방법

12버전: 기본적으로 page 컴포넌트는 클라이언트 컴포넌트이며 컴포넌트 외 함수들은 서버에서 실행 됨.

그러나 getStaticProps와 같이 static함수를 사용하면 페이지 전체가 SSG로 동작함

getServerSideProps를 사용하면 SSR로 동작함

import React from "react";

/** 클라이언트에서 동작 */
const Home = ({ test }: Props) => {
  return (
    <>
      <h1>Home</h1>
    </>
  );
};

export default Home;

/** 서버에서 동작 */
export const getStaticProps = async () => {
  const test = await getFetch()
  /** 컴포넌트로 전달하고 싶으면 props 형태로 만들어 전달해줘야 함 */
  return {
    props: { test },
    revalidate: 3 /** 옵션 설정하면 ISR */
  };
};

 

13버전: app 폴더 내 컴포넌트는 기본적으로 서버 컴포넌트임 (따라서 클라이언트 측의 상태를 이용할 수 없음)

generateStaticParams(12버전의 getServerSideProps와 getStaticPaths를 대체함)를 사용해 SSG로 동작시킬 수  있음

동적 경로 세그먼트에서 사용되는 fetch함수의 api는 반드시 절대 경로로 지정해야 한다!!

type FoodProps = {
  params: {
    slug: string;
  };
};

export const revalidate = 3;

const Foods = async ({ params: { slug } }: FoodProps) => {
  const food = await getFood(slug);
  if (!food) NotFound();
  return (
    <div style={{ height: "200vh" }}>
      <div>{food?.name}</div>;
      <Button />
    </div>
  );
};

export default Foods;

export const generateStaticParams = async () => {
  const foods = await getFoods();
  return foods.map((food) => ({ slug: food.id }));
};

CSR 방법

dynamic의 ssr옵션을 false로 설정

ISR 방법

revalidate

페이지에 아래 한 줄 입력해주면 됨

false (force-cache) : 기본값. 미리 가져온 데이터를 영구적으로 캐시하고 다시 유효성 검사를 수행하지 않음  (SSG)

0 : 캐시를 피하고 경로를 동적으로 렌더링.(SSR)

숫자 : 입력된 초마다 유효성을 검사.(ISR)

 

fetch 옵션 설정

next: {revalidate: 0 }

cache 옵션

  const res = await fetch('url~~', {
    // next: { revalidate: 0 },
    // cache: 'no-store'
  });

dynamic 설정

import { searchUsers } from '@/service/user';
import { NextResponse } from 'next/server';

export async function GET() {
  return searchUsers().then((data) => NextResponse.json(data));
}

위처럼 request없이 정적으로 작동하는 코드는 SSG로 행동함.

만약 전체 유저를 불러오는 페이지가 SSG로 작동한다면 신규 가입자가 나타나지 않는 문제가 발생함

이런 경우 dynamic를 설정해 렌더링 방식을 바꿀 수 있음

// src\app\api\search\route.ts

import { searchUsers } from '@/service/user';
import { NextResponse } from 'next/server';

export const dynamic = 'force-dynamic';
// 'auto' | 'force-dynamic' | 'error' | 'force-static' (기본값 auto)

export async function GET() {
  return searchUsers().then((data) => NextResponse.json(data));
}
// src\app\search\page.tsx

import UserSearch from "@/components/userSearch";
import { Metadata } from "next";

export const metadata: Metadata = {
  title: 'User Search',
  description: 'Search users to follow',
};

export const dynamic = 'force-dynamic';

export default function SearchPage() {
  return <UserSearch />;
}

 

실시간 SSR 업데이트

만약 클라이언트 컴포넌트에서 바뀐 상태에 따라 서버 컴포넌트 역시 그것이 반영이 되어야 할 경우 아래 방법을 사용해 실시간 업데이트를 할 수 있다.

  const router = useRouter();
  const [isPending, startTransition] = useTransition();
  const [isFetching, setIsFetching] = useState(false);
  
  const handleFollow = async () => {
    setIsFetching(true);
    await toggleFollow(user.id, !following);
    setIsFetching(false);
    startTransition(() => {
      router.refresh();
    });
  };

위 방법은 임시적인 방법으로 현재는 아래의 실험적인 방식으로 바뀐 상태.

그러나 해보니 서버 상태 관리 라이브러리와 같이 사용하게 되는 경우 아직 한계가 있는 것 같다.

https://nextjs.org/docs/app/building-your-application/data-fetching/server-actions

 

Data Fetching: Server Actions | Next.js

Server Actions are an alpha feature in Next.js, built on top of React Actions. They enable server-side data mutations, reduced client-side JavaScript, and progressively enhanced forms. They can be defined inside Server Components and/or called from Client

nextjs.org

 

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

Next.js 심화  (0) 2023.06.20
라우팅 심화  (0) 2023.06.12
리액트에서 사용했던 기능들  (0) 2023.06.07
API 백엔드 로직  (0) 2023.06.06
Next.js 기본  (0) 2023.06.02
Comments