[Next.js] 렌더링 방식 선택
렌더링 방식 비교
| 방식 | 실행 시점 | 속도 | 최신성 | 비용 | 용도 |
|---|---|---|---|---|---|
| SSG | 빌드 타임 | ⚡⚡⚡ | 낮음 | 저 | 정적 콘텐츠 |
| ISR | 빌드 + 주기적 | ⚡⚡ | 중간 | 저 | 블로그, 제품 목록 |
| SSR | 매 요청 | ⚡ | 높음 | 중 | 실시간 데이터 |
| SSR + 캐싱 | 매 요청 (캐시) | ⚡⚡ | 중간 | 저 | 사용자별 데이터 |
| CSR | 클라이언트 | ⚡ | 높음 | - | 상태, 인터랙션 |
Server Component vs Client Component
tsx
// Server Component (기본) - SSG/SSR
async function ProfileSection() {
const data = await prisma.user.findFirst()
return <div>{data.name}</div>
}
// Client Component - CSR
'use client'
function Counter() {
const [count, setCount] = useState(0)
return <button onClick={() => setCount(count + 1)}>{count}</button>
}ISR (Incremental Static Regeneration)
정적 페이지를 빌드 후에도 일정 시간마다 자동으로 재생성
tsx
export const revalidate = 3600 // 1시간마다 재생성
export default async function PostPage({ params }) {
const post = await prisma.post.findUnique({
where: { slug: params.slug }
})
return <MarkdownRenderer content={post.content} />
}ISR 옵션:
- revalidate = 3600 - 1시간마다 재생성
- revalidate = false - ISR 비활성화 (순수 SSG)
- revalidate = 0 - 매 요청마다 (SSR과 유사)
SSR + 캐싱
매 요청마다 렌더링하지만, 캐시 유효 기간 내 동일 요청은 재사용
text
첫 번째 요청: 요청 → DB 쿼리 → 렌더링 → 캐시 저장 (1초)
캐시 내 요청: 요청 → 캐시 반환 (1ms) ⚡
캐시 만료 후: 요청 → DB 쿼리 → 렌더링 → 캐시 갱신 (1초)tsx
export const revalidate = 60 // 60초
async function UserDashboard({ userId }) {
const data = await prisma.user.findUnique({
where: { id: userId }
})
return <div>{data.name}</div>
}컴포넌트 단위 선택
Next.js는 페이지/컴포넌트 단위로 렌더링 방식 선택 가능
tsx
// 현재 프로젝트 구조
CollapsibleSidebar (Server Component - SSR)
└─ SidebarContent (Client Component - CSR)
└─ profile data는 서버에서 전달
// 최적 패턴
async function Page() {
const data = await fetchData()
return (
<div>
<StaticContent data={data} /> {/* Server */}
<InteractiveWidget data={data} /> {/* Client */}
</div>
)
}현재 프로젝트 추천 전략
| 페이지/컴포넌트 | 추천 방식 | 이유 |
|---|---|---|
| 블로그 글 | SSG (ISR) | 글은 자주 안 바뀜 |
| 글 목록 | SSG (ISR) | 새 글 시간당 몇 개 |
| 프로필 페이지 | SSG | 프로필 거의 안 바뀜 |
| About 페이지 | SSG | 정적 콘텐츠 |
| 사용자 대시보드 | SSR + 캐싱 | 사용자마다 다름 |
| 검색 결과 | SSR | 매번 다른 결과 |
| 상호작용 요소 | CSR | 상태, 이벤트 핸들러 |
핵심 정리
프로젝트 개선사항
✅ 프로필 이미지 SSR로 전환 ✅ 부드러운 UI 트랜지션 추가 ✅ 마크다운 인라인 코드 렌더링 수정 ✅ Server/Client Component 최적 분리
배운 개념
- Next.js App Router의 Server/Client Component 분리
- SSG, ISR, SSR의 차이와 선택 기준
- Tailwind CSS의 @apply와 transition
- 마크다운 렌더러 커스터마이징
Best Practice
- 기본은 Server Component - 필요할 때만 CSR 적용
- 프로필 데이터는 SSR - 모든 페이지에서 동일하므로 최상단에서 fetch
- 상태 관리는 Client Component - localStorage, useState 등
- ISR 활용 - 블로그 글은 시간 주기로 재생성하여 성능과 최신성 모두 확보
댓글을 불러오는 중...