Next.js는 왜 서버 컴포넌트에서 데이터 호출을 권장할까?
Next.js 13 서버 컴포넌트
Next.js 13부터 app/ 디렉토리와 함께 등장한 서버 컴포넌트(Server Components)는 많은 변화를 가져왔습니다.
그 중 하나가 바로 데이터 패칭의 위치에 대한 새로운 권장 방식입니다.
타입 | 설명 |
---|---|
서버 컴포넌트 (.tsx, 기본) | 데이터 fetch, DB 접근, SEO에 적합 |
클라이언트 컴포넌트 (“use client”) | 상태 관리, 이벤트 핸들링 등 UI 상호작용 담당 |
✅ 왜 서버 컴포넌트에서 데이터를 불러오라고 할까? 서버에서 데이터를 불러오면 어떤 이점이 있을까요?
이유 | 설명 |
---|---|
보안 | API 키, DB 토큰 등 민감 정보는 서버에서만 사용 → 클라이언트에 노출되지 않음 |
성능 | 서버에서 먼저 데이터를 준비해서 클라이언트에 렌더된 HTML로 제공 → 초기 로딩 빠름 |
SEO | 클라이언트에서 fetch하는 방식은 크롤러가 내용을 인식하기 어려움 → 서버 렌더가 유리 |
내장 캐싱 지원 | Next.js의 fetch는 revalidate, cache, no-store 등 다양한 캐싱 전략 내장 |
불필요한 JS 줄이기 | 클라이언트에서 무거운 fetch 로직이 없어짐 → 번들 사이즈 감소 |
🔍 반대로 클라이언트에서 fetch할 경우 생기는 문제
로딩 시간 증가 → 화면 진입 시 빈 UI → useEffect로 fetch → 느려짐
SEO 손실 → 화면은 비었는데 크롤러가 보는 건 JS 뿐
보안 취약 → API 호출 시 인증 토큰/키가 클라이언트에 노출될 수 있음
캐싱 어려움 → React Query 등의 라이브러리를 사용하더라도 Next.js의 fetch() 캐싱 전략은 활용 불가
React Query 데이터 패칭
React Query는 클라이언트에서 다음 역할을 해줍니다.
캐시된 데이터를 빠르게 보여줌
포커스 시 자동 리패치
오류 처리, 로딩 상태 등 핸들링
사용자 액션 기반 추가 fetch 처리 (검색, 필터 등)
1
2
3
4
5
6
7
8
9
10
// 서버 컴포넌트 (page.tsx)
const queryClient = new QueryClient();
await queryClient.prefetchQuery({ queryKey: ["interestZones"], queryFn: fetchZones });
const dehydratedState = dehydrate(queryClient);
return (
<Hydrate state={dehydratedState}>
<ClientComponent />
</Hydrate>
);
1
2
3
// 클라이언트 컴포넌트
"use client";
const { data } = useQuery({ queryKey: ["interestZones"], queryFn: fetchZones });
이 구조는 서버에서 모든 필요한 데이터를 fetch 클라이언트 컴포넌트는 캐시만 사용 (useQuery + hydrate) 이다.
장점 | 설명 |
서버 fetch | 보안, SEO, 초기 속도 모두 이득 |
클라이언트에서는 캐시 사용만 | 추가 네트워크 요청 없음 |
React Query의 생태계 활용 | 리패치, 캐시 시간, 오류 처리 등 그대로 사용 가능 |
CSR/SSR 유연하게 전환 가능 | prefetch 없는 경우엔 자동 클라이언트 fetch로 fallback |
컴포넌트 단위 데이터 패칭 전략
1️⃣ 페이지 단위 데이터 패칭 (Page-level Fetching) 서버 컴포넌트에서 모든 필요한 데이터를 한꺼번에 불러오고 하위 컴포넌트에는 props로 전달하는 방식
🧩 적합한 상황
- 초기 진입 시 반드시 필요한 데이터
- SEO가 중요한 콘텐츠 (뉴스, 상세 페이지 등)
- 서버 렌더링이 유리한 경우
2️⃣ 컴포넌트 단위 데이터 패칭 (Component-level Fetching) 클라이언트 컴포넌트에서 useQuery, useEffect 등을 통해 컴포넌트 내부에서 직접 데이터를 fetch
🧩 적합한 상황
- 사용자 상호작용 이후 로딩되는 데이터 (예: 댓글, 필터)
- modal / tab 내부 콘텐츠
- 페이지와 무관한 유틸성 UI
정리해서 기억하면 좋은 기준
판단 기준 | fetch 위치 |
---|---|
초기 진입 시 항상 필요함 | page.tsx 서버에서 prefetch + hydrate |
특정 조건/행동 후 필요 | 클라이언트 컴포넌트 내 fetch |
SEO 중요 + 빠른 로딩 필요 | 서버 fetch |
사용자의 동적 행동 기반 데이터 | 클라이언트 fetch |