가수면
SSR, SSG, ISR, CSR 방법 본문
클라이언트 컴포넌트, 서버 컴포넌트 선택 기준
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 |