기본 방식
기본적으로 서버 사이드 방식과 클라이언트 사이드 방식을 모두 지원하는 하이브리드 프레임워크입니다. 즉, 어떤 방식으로 페이지를 렌더링할지는 개발자가 설정에 따라 선택할 수 있습니다. 기본적으로 Next.js는 SSG(Static Site Generation)와 SSR(Server-Side Rendering) 방식을 모두 제공하며, 클라이언트 사이드의 동적 기능도 지원
요약
기본적으로 서버 사이드 방식: Next.js는 서버 사이드에서의 페이지 렌더링을 기본적으로 제공하며, SSG와 SSR을 지원
클라이언트 사이드 지원: Next.js는 또한 클라이언트 사이드 기능도 지원하며, 동적 임포트, 클라이언트 사이드 라우팅, API Routes 등 다양한 클라이언트 사이드 기술을 제공
데이터 패칭 방식
1. SSG (Static Site Generation)
- 개요: 빌드 시점에 데이터를 가져와 HTML 파일을 생성합니다. 페이지 요청 시 서버는 정적 HTML 파일을 제공하므로 빠른 속도를 자랑합니다.
- 사용 방법: getStaticProps를 사용하여 데이터를 미리 가져옵니다.
- 장점: 빠른 페이지 로딩 속도, SEO 최적화.
- 단점: 페이지가 빌드 시에만 생성되므로, 데이터가 실시간으로 갱신되지 않습니다.
export async function getStaticProps() {
const data = await fetchDataFromAPI();
return {
props: { data }
};
}
2. SSR (Server-Side Rendering)
- 개요: 요청이 있을 때마다 서버에서 데이터를 가져와 페이지를 동적으로 렌더링합니다. 매 요청 시마다 새로운 HTML을 생성합니다.
- 사용 방법: getServerSideProps를 사용하여 요청 시마다 데이터를 가져옵니다.
- 장점: 항상 최신 데이터를 제공합니다.
- 단점: 서버에서 매번 페이지를 렌더링하므로 성능에 부담을 줄 수 있습니다.
export async function getServerSideProps() {
const data = await fetchDataFromAPI();
return {
props: { data }
};
}
3. ISR (Incremental Static Regeneration)
- 개요: SSG와 유사하지만, 페이지를 일정 주기마다 재생성할 수 있습니다. 이를 통해 정적 페이지의 성능과 동적 페이지의 유연성을 동시에 갖출 수 있습니다.
- 사용 방법: getStaticProps와 revalidate 속성을 사용하여 페이지를 주기적으로 재생성합니다.
- 장점: 초기에는 정적 페이지로 제공되며, 이후 변경된 페이지만 재생성하므로 성능이 뛰어납니다.
- 단점: 초기 빌드 후, 일정 시간 동안 페이지가 갱신되지 않을 수 있습니다.
export async function getStaticProps() {
const data = await fetchDataFromAPI();
return {
props: { data },
revalidate: 60, // 60초마다 페이지를 재생성
};
}
요약
- SSG: 빌드 시에 페이지를 미리 생성.
- SSR: 요청마다 서버에서 페이지를 동적으로 생성.
- ISR: 정적 페이지를 주기적으로 재생성하여 성능과 최신 데이터의 장점 결합.
- 동적 임포트: 코드 분할을 통해 필요할 때만 추가적인 코드 로드.
방식 | 설명 | 실행 위치 | 언제 실행되는지 |
SSG (Static Site Generation) | 빌드 시에 데이터를 가져와 정적 페이지를 생성. | 서버 사이드 | 빌드 시에 한 번만 실행되어 정적 HTML을 생성 |
SSR (Server-Side Rendering) | 요청 시마다 데이터를 가져와 동적 페이지를 생성. | 서버 사이드 | 페이지 요청 시마다 서버에서 실행되어 동적 페이지를 생성 |
ISR (Incremental Static Regeneration) | 정적 페이지를 주기적으로 재생성하여 성능과 최신 데이터를 결합. | 서버 사이드 | 페이지가 요청될 때마다 또는 설정된 주기에 따라 서버에서 페이지를 재생성 |
데이터를 가져오는 주요 함수
페이지를 렌더링하기 위해 데이터를 가져오는 데 사용되는 주요 함수들인 getStaticProps, getServerSideProps, getStaticPaths, revalidate
1. getStaticProps (Static Site Generation)
- 설명: 이 함수는 페이지를 정적으로 생성할 때 데이터를 가져오는 데 사용됩니다. Next.js는 빌드 시 이 함수를 실행하여 데이터를 미리 가져오고, 이를 바탕으로 정적 HTML 파일을 생성합니다. 이후 해당 페이지는 서버 없이 빠르게 제공됩니다.
- 주요 사용 사례: 콘텐츠가 자주 변하지 않는 페이지 (예: 블로그 게시물, 문서 등)
- getStaticProps는 async 함수여야 하며, 반드시 props를 반환해야 합니다.
- 데이터를 가져오는 데 시간이 오래 걸리는 경우 API 호출이나 DB 쿼리 등을 수행할 수 있습니다.
export async function getStaticProps() {
const data = await fetchDataFromAPI();
return {
props: { data }, // 페이지에 전달할 데이터
};
}
- 장점:
- 빠른 페이지 로딩 (정적 파일을 제공하므로).
- SEO 최적화가 용이.
- 단점:
- 데이터가 빌드 시에만 고정되므로, 실시간 데이터 변경이 필요하면 적합하지 않음.
2. getServerSideProps (Server-side Rendering)
- 설명: 이 함수는 서버에서 동적으로 페이지를 렌더링할 때 사용됩니다. 페이지 요청이 있을 때마다 Next.js는 이 함수가 실행되어 데이터를 가져온 후 서버에서 HTML을 생성하여 클라이언트에 전송합니다.
- 주요 사용 사례: 실시간 데이터가 필요한 페이지 (예: 사용자 맞춤형 대시보드, 검색 결과 등)
- 사용법:
- getServerSideProps도 async 함수로 정의되며, props를 반환해야 합니다.
- 매 요청 시마다 데이터를 갱신하므로 항상 최신 데이터를 제공합니다.
export async function getServerSideProps() {
const data = await fetchDataFromAPI();
return {
props: { data }, // 페이지에 전달할 데이터
};
}
- 장점:
- 항상 최신 데이터를 제공할 수 있음.
- 단점:
- 서버에서 매번 페이지를 렌더링해야 하므로 성능이 떨어질 수 있음.
- 페이지 로딩 시간이 느려질 수 있음.
3. getStaticPaths (SSG with Dynamic Routes)
- 설명: 이 함수는 동적 라우트와 함께 사용되어야 합니다. 페이지가 동적으로 생성되는 경우 (예: [id].js와 같은 동적 라우트), Next.js는 어떤 페이지를 생성해야 할지 알지 못합니다. getStaticPaths는 어떤 경로들을 빌드할지 알려주기 위한 함수입니다.
- 주요 사용 사례: 동적 경로를 사용하는 페이지 (예: 블로그 포스트, 상품 페이지 등)
- 사용법:
- getStaticPaths는 동적 경로의 목록을 반환합니다.
- getStaticProps와 함께 사용되며, getStaticPaths에서 제공하는 경로에 대해 getStaticProps가 실행됩니다.
export async function getStaticPaths() {
const paths = await fetchPathsFromAPI();
return {
paths, // 동적 경로 목록
fallback: 'blocking', // 페이지가 빌드되지 않은 경우 대처 방식
};
}
export async function getStaticProps({ params }) {
const data = await fetchDataForPage(params.id);
return {
props: { data },
};
}
- fallback 옵션:
- false: 빌드되지 않은 경로에 대한 요청은 404를 반환합니다.
- true: 빌드되지 않은 경로를 요청하면 빈 페이지를 보여주고, 페이지가 생성된 후 다시 렌더링합니다.
- blocking: 빌드되지 않은 경로를 요청하면, 페이지가 준비될 때까지 기다린 후 반환합니다.
- 장점:
- 동적 경로에 대한 SSG를 사용할 수 있어 성능이 우수합니다.
- 단점:
- 동적 경로가 많은 경우, 빌드 시간이 길어질 수 있습니다.
방식 | 설명 | 실행 위치 | 언제 실행되는지 |
getStaticProps | 빌드 시에 데이터를 가져와 정적 페이지를 생성. | 서버 사이드 | 빌드 시에 실행되어 데이터를 가져오고 정적 HTML을 생성 |
getServerSideProps | 요청 시마다 데이터를 가져와 동적 페이지를 생성. | 서버 사이드 | 페이지 요청 시마다 실행되어 동적 HTML을 생성 |
getStaticPaths | 동적 경로를 사용하는 페이지에서 어떤 경로들을 생성할지 정의. | 서버 사이드 | 빌드 시에 실행되어 동적 경로 목록을 반환 |
revalidate (ISR) | 정적 페이지를 일정 주기마다 재생성하여 최신 데이터를 반영 (ISR). | 서버 사이드 | 설정된 주기마다 정적 페이지를 재생성하여 최신 데이터 반영 |
데이터 패칭 방식
1. 클라이언트 사이드 데이터 패칭
- 설명: 클라이언트 사이드에서는 데이터 요청이 브라우저에서 직접 이루어집니다. 즉, 페이지가 로드된 후 JavaScript를 사용하여 API를 호출하거나 데이터를 가져옵니다. 이 방식은 보통 사용자 인터랙션 이후 데이터를 동적으로 불러오는 데 사용됩니다.
- 주요 특징:
- 브라우저에서 실행: 클라이언트 측에서 JavaScript가 실행되며 API를 호출하거나 데이터를 가져옵니다.
- 동적 업데이트: 페이지가 처음 로드될 때는 기본적인 HTML과 JavaScript 파일만 로드되고, 이후에 필요한 데이터는 비동기적으로 가져옵니다.
- SEO: 클라이언트 사이드에서 데이터를 가져오기 때문에, 검색 엔진이 페이지의 초기 HTML을 크롤링할 때는 데이터가 없을 수 있습니다. 따라서 SEO에 불리할 수 있습니다.
- 장점:
- 페이지 로딩 속도가 빠를 수 있음 (첫 번째 요청은 빠르고, 이후 데이터만 비동기적으로 가져옴).
- 서버 리소스를 덜 사용하고, 클라이언트에서만 데이터를 처리.
- 단점:
- SEO 최적화가 어려울 수 있음.
- 처음 페이지를 로드할 때 빈 화면 또는 로딩 상태를 표시해야 할 수 있음.
- 예시: 클라이언트에서 데이터를 비동기적으로 가져오는 예시 (React의 useEffect와 fetch 사용)
import { useEffect, useState } from 'react';
const MyComponent = () => {
const [data, setData] = useState(null);
useEffect(() => {
fetch('/api/data')
.then(response => response.json())
.then(data => setData(data));
}, []);
if (!data) {
return <div>Loading...</div>;
}
return <div>{data}</div>;
};
2. 서버 사이드 데이터 패칭
- 설명: 서버 사이드에서는 서버에서 데이터를 가져옵니다. Next.js와 같은 서버 사이드 렌더링(SSR) 프레임워크는 요청이 있을 때마다 서버에서 데이터를 처리하고 HTML을 동적으로 렌더링합니다. 데이터는 클라이언트로 보내기 전에 서버에서 미리 준비되어 페이지에 포함됩니다.
- 주요 특징:
- 서버에서 실행: 서버가 페이지를 렌더링할 때 데이터를 가져오고, 페이지를 완성하여 클라이언트에 보냅니다.
- SEO 최적화: 서버에서 데이터를 처리하여 HTML을 반환하므로 검색 엔진이 페이지를 크롤링할 때 이미 렌더링된 페이지를 볼 수 있습니다. SEO에 유리합니다.
- 초기 로딩: 페이지가 서버에서 완전히 렌더링되어 전달되므로, 클라이언트가 페이지를 처음 로드할 때 데이터가 이미 준비되어 있습니다.
- 장점:
- SEO 최적화: 초기 HTML에 데이터가 포함되어 있어 검색 엔진에 최적화됩니다.
- 초기 렌더링 시 데이터가 모두 준비되어 있기 때문에 사용자가 기다릴 필요가 없습니다.
- 단점:
- 서버에 부하가 발생할 수 있음 (매번 요청 시마다 데이터를 처리하고 페이지를 렌더링).
- 서버 리소스를 많이 사용하므로 성능에 영향을 줄 수 있음.
- 예시: getServerSideProps를 사용한 서버 사이드 데이터 패칭 예시
export async function getServerSideProps() {
const data = await fetchDataFromAPI();
return {
props: { data }
};
}
const MyPage = ({ data }) => {
return <div>{data}</div>;
};
클라이언트 사이드 vs 서버 사이드 데이터 패칭 차이
특징 | 클라이언트 사이드 데이터 패칭 | 서버사이드 데이터 패칭 |
데이터 요청 위치 | 브라우저 (클라이언트 측) | 서버 측 (서버에서 데이터를 가져오고 렌더링 후 클라이언트로 전달) |
초기 렌더링 시 데이터 | 첫 로딩 시 빈 화면 또는 로딩 상태 표시 | 페이지가 서버에서 미리 렌더링되어 클라이언트에 완전한 HTML 전달 |
SEO | SEO에 불리할 수 있음 (데이터가 자바스크립트 실행 후 로드되므로) | SEO에 유리함 (서버에서 렌더링된 HTML을 제공하므로 검색 엔진에 최적화) |
성능 | 페이지 로딩 후 데이터를 비동기적으로 가져와 처리 (빠른 로딩) | 서버에서 매 요청마다 데이터를 처리하므로 서버 부하 발생 가능 |
사용 사례 | 실시간 데이터 업데이트가 필요한 UI, 사용자 상호작용 후 데이터 로드 | 페이지 초기 로딩 시 데이터가 필요하거나 SEO 최적화가 중요한 페이지 |
CSR / UseEffect를 사용하는 방식
클라이언트 측 렌더링 방식으로, 웹 페이지의 콘텐츠가 브라우저에서 직접 렌더링되는 방법입니다. 즉, 초기 HTML 페이지는 최소한의 구조만 포함하고, 그 이후 필요한 JavaScript 파일을 로드하여 데이터를 가져오고 페이지를 동적으로 렌더링하는 방식
CSR (Client-Side Rendering) 특징
1. 초기 로딩
- CSR에서는 최초 요청 시 서버에서 빈 HTML과 JavaScript만 제공하고, 실제 콘텐츠는 JavaScript가 실행되고 데이터를 가져온 후 렌더링됩니다.
- 서버에서 HTML을 미리 렌더링하지 않음으로써 초기 렌더링이 느려질 수 있습니다. 즉, 브라우저가 JavaScript를 다운로드하고 실행할 때까지는 페이지의 실제 콘텐츠가 표시되지 않습니다.
2. 데이터 가져오기
- CSR 방식에서는 페이지가 로드된 후, JavaScript가 클라이언트에서 데이터를 비동기적으로 가져옵니다. 일반적으로 fetch나 axios와 같은 API를 통해 서버에서 데이터를 가져옵니다.
- 이때 사용되는 데이터는 주로 AJAX나 REST API, GraphQL 등을 통해 클라이언트 측에서 요청됩니다.
3. 페이지 동적 렌더링
- 클라이언트에서 데이터를 받아와 동적으로 HTML을 생성하여 렌더링합니다. 이는 React, Vue.js, Angular 등과 같은 SPA (Single Page Application) 프레임워크에서 사용됩니다.
- 페이지 전환 시 서버로부터 새로운 페이지를 로드하지 않고, 클라이언트 내에서 JavaScript가 DOM을 수정하여 페이지를 업데이트합니다.
4. 라우팅
- CSR에서는 클라이언트 측 라우팅을 사용합니다. 즉, 페이지가 바뀔 때 서버로 새로운 요청을 보내지 않고 JavaScript가 URL을 처리하여 필요한 콘텐츠를 클라이언트 측에서 가져옵니다.
- React에서는 react-router-dom과 같은 라이브러리를 통해 클라이언트 측 라우팅을 구현합니다.
CSR 장점
- 빠른 페이지 전환:
- 첫 페이지 로딩 후 클라이언트에서 페이지를 동적으로 렌더링하므로, 이후의 페이지 전환은 서버 요청 없이 매우 빠르게 일어납니다. 이는 주로 SPA 애플리케이션에서 큰 장점입니다.
- 서버 부하 감소:
- 모든 페이지 렌더링을 클라이언트에서 처리하므로, 서버는 초기 HTML과 JavaScript만 제공하고 페이지 렌더링은 클라이언트에서 수행되기 때문에 서버 부하가 줄어듭니다.
- 동적인 사용자 경험:
- 클라이언트에서 JavaScript가 데이터를 가져오고 DOM을 업데이트하므로, 사용자에게 동적이고 반응성이 뛰어난 경험을 제공합니다. 예를 들어, 애니메이션, 실시간 업데이트 등 클라이언트 사이드에서 효율적으로 처리할 수 있습니다.
- SEO와 서버 사이드 로딩 없이 빠른 사용자 경험 제공:
- 앱의 첫 페이지가 로드된 이후, 사용자가 페이지를 이동하거나 데이터를 가져오는 데 있어 서버 요청 없이 빠른 반응을 보장합니다. 이 점은 사용자 경험(UX)을 향상시킵니다.
CSR 단점
- 초기 로딩 시간 지연:
- CSR 방식에서는 처음 페이지가 로드될 때 JavaScript 파일을 다운로드하고 실행해야 하므로, 첫 번째 페이지 로딩 속도가 상대적으로 느릴 수 있습니다. 특히 대용량의 JavaScript 파일을 다운로드해야 할 경우, 로딩 시간이 길어질 수 있습니다.
- 또한, 초기 페이지 로딩 시 SEO가 중요한 페이지에서는 문제가 될 수 있습니다.
- SEO (검색 엔진 최적화):
- CSR 방식은 초기 HTML이 빈 페이지와 같은 상태로 로드되기 때문에, 검색 엔진 봇이 페이지 내용을 인식하는 데 어려움이 있을 수 있습니다. 이는 SEO에 불리한 점이 됩니다.
- 서버 사이드 렌더링(SSR) 방식이나 정적 사이트 생성(SSG) 방식은 초기 HTML에 콘텐츠가 포함되므로 검색 엔진 최적화에 유리합니다.
- JavaScript 의존성:
- CSR은 JavaScript 실행에 의존하므로, 만약 사용자가 JavaScript를 비활성화하거나 지원하지 않는 환경이라면 페이지가 제대로 작동하지 않거나 빈 화면이 표시될 수 있습니다.
- 브라우저 성능 문제:
- 클라이언트에서 모든 렌더링을 처리하기 때문에, 성능이 낮은 디바이스에서는 느려지거나 반응 속도가 떨어질 수 있습니다. 특히 복잡한 애플리케이션에서는 클라이언트에서의 렌더링 부담이 커질 수 있습니다.
CSR 사용 시 적합한 경우
- 동적인 사용자 경험이 필요한 경우 (예: 실시간 데이터 업데이트, 사용자 상호작용에 따른 변화).
- SEO가 크게 중요하지 않은 애플리케이션.
- 상호작용이 많고 복잡한 UI를 처리해야 하는 애플리케이션.
- 사용자가 페이지 전환 후 빠른 반응을 기대하는 경우 (예: 대시보드 애플리케이션, 채팅 애플리케이션 등).
결론
언제 SSR, CSR, SSG를 사용할지 요약
랜더링 방식 | 사용 시점 | 예시 페이지 |
SSR (서버 사이드) | 실시간 데이터 필요 + SEO가 중요한 페이지 | 블로그, 뉴스 페이지, 마케팅 페이지 |
CSR (클라이언트 사이드) | SEO가 필요 없고 사용자 상호작용이 많은 페이지 | 대시보드, 채팅, 개인화된 페이지 |
SSG (정적 사이트) | 자주 바뀌지 않는 콘텐츠를 미리 렌더링 (SEO 최적화) | 블로그 글, 문서 페이지 |
ISR (재생성) | 최신 데이터를 주기적으로 반영하면서 정적 페이지 유지 | 상품 목록, 자주 업데이트되는 게시글 |
페이지마다 적절히 분리해서 사용하는 것이 중요합니다. 이렇게 하면 성능 최적화와 사용자 경험(UX), SEO를 모두 만족
페이지마다 SSR과 CSR을 분리해야 하는 이유
- SEO가 중요한 페이지 → SSR (Server-Side Rendering)
- 서버에서 HTML을 미리 렌더링해서 브라우저에 제공하므로, 검색 엔진이 콘텐츠를 쉽게 크롤링할 수 있습니다.
- 예: 블로그, 뉴스 페이지, 상품 상세 페이지와 같이 SEO가 중요한 페이지.
- SEO가 중요하지 않은 페이지 → CSR (Client-Side Rendering)
- 데이터를 클라이언트에서 동적으로 가져오고 렌더링하는 방식입니다. 초기 로딩은 느릴 수 있지만 이후 빠른 페이지 전환이 가능합니다.
- 예: 사용자 개인화 대시보드, 관리 화면, 실시간 업데이트가 많은 페이지 등.
- 성능 최적화 → SSG + ISR (Static Site Generation + Incremental Static Regeneration)
- 데이터를 빌드 시점에 정적으로 생성하거나, revalidate를 활용해 주기적으로 최신 데이터로 재생성할 수 있습니다.
- 예: 블로그 목록 페이지, 자주 변경되지 않는 콘텐츠 페이지.
'Next.js' 카테고리의 다른 글
Client와 Server 컴포넌트의 상태 관리 (0) | 2024.12.18 |
---|---|
Next.js 14 프로젝트 구조 및 아키텍처 설계 (1) | 2024.12.18 |
기능/페이지별 데이터 패칭 전략 (0) | 2024.12.17 |