1. 렌더링 패턴 종류
1. Client-Side Rendering (CSR)
- 설명: 리액트의 전통적인 방식으로 SPA(Single Page Application)에서 클라이언트 측에서 동적으로 페이지를 렌더링.
- 장점:
- 최초 로딩 후 사용자와의 상호작용이 빠르고 부드럽다.
- 서버 부하가 적고, 서버 요청 없이도 동작 가능.
- MPA(Multi Page Application)에서 발생했던 깜빡거림 문제를 해결.
- 단점:
- 초기 로딩 시간이 길어질 수 있음.
- SEO 최적화가 어려움(검색 엔진이 CSR을 완전히 지원하지 않는 경우가 있음).
2. Static Site Generation (SSG)
- 설명: 정적인 페이지를 빌드 타임에 미리 생성하여 제공.
- 장점:
- **TTV(Time To View)**가 짧고 SEO 최적화에 유리.
- CDN 캐싱 가능.
- 서버 부하가 적음.
- 단점:
- 데이터 의존적인 페이지(예: 마이페이지) 구현이 불가능.
- 빌드 시간이 길어질 수 있음.
- 정적 페이지이기 때문에 실시간 데이터 갱신이 어려움.
3. Incremental Static Regeneration (ISR)
- 설명: SSG의 단점을 보완하여, 설정한 주기마다 정적 페이지를 다시 생성.
- 장점:
- SSG처럼 빠른 초기 로딩 속도.
- 일정 시간 간격으로 콘텐츠 업데이트 가능.
- CDN 캐싱 가능.
- 단점:
- 실시간 데이터 업데이트에는 한계.
- 데이터 의존적인 페이지 구현에는 부적합.
4. Server-Side Rendering (SSR)
- 설명: 클라이언트의 요청마다 서버에서 HTML을 생성하여 제공.
- 장점:
- SEO 최적화 및 실시간 데이터 갱신 가능.
- 데이터 의존적인 페이지(예: 마이페이지) 구현 가능.
- 보안성이 높음.
- 단점:
- 요청마다 서버 렌더링이 발생하므로 서버 부하 증가.
- CDN 캐싱이 제한적.
2. 코드 구현
1. SSG (Static Site Generation)
- Next.js에서 기본 설정으로 동작.
- HTML은 빌드 타임에 생성되며, 클라이언트 요청 시 정적인 페이지를 제공.
export const getStaticProps = async () => {
const res = await fetch("http://localhost:4000/products");
const products = await res.json();
return {
props: { products },
};
};
const Home = ({ products }: { products: Product[] }) => {
return (
<div>
{products.map((product) => (
<div key={product.id}>
<h2>{product.title}</h2>
<p>{product.price.amount}$</p>
</div>
))}
</div>
);
};
export default Home;
2. SSR (Server-Side Rendering)
- **cache: "no-store"**를 설정하여 클라이언트 요청마다 서버에서 데이터를 가져옴.
- 실시간 데이터가 필요한 경우 적합.
export const getServerSideProps = async () => {
const res = await fetch("http://localhost:4000/products", {
cache: "no-store",
});
const products = await res.json();
return {
props: { products },
};
};
const Home = ({ products }: { products: Product[] }) => {
return (
<div>
{products.map((product) => (
<div key={product.id}>
<h2>{product.title}</h2>
<p>{product.price.amount}$</p>
</div>
))}
</div>
);
};
export default Home;
3. ISR (Incremental Static Regeneration)
- revalidate를 설정하여 주기적으로 정적 페이지를 갱신.
export const getStaticProps = async () => {
const res = await fetch("http://localhost:4000/products");
const products = await res.json();
return {
props: { products },
revalidate: 3, // 3초마다 정적 페이지 갱신
};
};
const Home = ({ products }: { products: Product[] }) => {
return (
<div>
{products.map((product) => (
<div key={product.id}>
<h2>{product.title}</h2>
<p>{product.price.amount}$</p>
</div>
))}
</div>
);
};
export default Home;
4. CSR (Client-Side Rendering)
- 클라이언트에서 데이터를 가져와 렌더링.
- 브라우저에서 비동기로 데이터를 요청.
"use client";
import React, { useEffect, useState } from "react";
import { Product } from "../page";
const ProductList = () => {
const [data, setData] = useState<Product[]>([]);
useEffect(() => {
const fetchData = async () => {
const res = await fetch("http://localhost:4000/products");
const products = await res.json();
setData(products);
};
fetchData();
}, []);
return (
<div>
{data.map((product) => (
<div key={product.id}>
<h2>{product.title}</h2>
<p>{product.price.amount}$</p>
</div>
))}
</div>
);
};
export default ProductList;
3. 언제 각각의 렌더링 패턴을 사용해야하는지...
CSR |
사용자와의 상호작용이 많고, SEO가 덜 중요한 경우 |
SSG |
콘텐츠가 정적이고 자주 변경되지 않는 경우 |
ISR |
콘텐츠가 주기적으로 갱신되고 실시간 반영이 필요하지 않은 경우 |
SSR |
실시간 데이터 갱신과 SEO가 중요한 경우 |