
이전 포스트에서 useEffect를 사용한 클라이언트 측 데이터 페칭 방식을 살펴보았습니다. 이 방식은 React에서 일반적이지만, Next.js의 진정한 장점을 활용하는 최적의 방법은 아닙니다.
Next.js에서는 모든 페이지 컴포넌트가 기본적으로 React 서버 컴포넌트(RSC)로 작동하며, 이를 활용하여 데이터를 서버에서 직접 가져올 수 있습니다. 이 방법을 통해 코드가 훨씬 간결해지고, 중요한 이점을 얻을 수 있습니다.
1. 서버 컴포넌트 데이터 페칭 코드 예시와 변화
서버 컴포넌트 방식을 사용하면, 클라이언트 컴포넌트에서 필수였던 useState와 useEffect를 모두 제거하고 코드를 극적으로 간결하게 만들 수 있습니다.
a. 코드 구조: async 키워드와 직접 fetch
NewsPage 컴포넌트 함수에 **$\text{async}$**를 붙여 비동기 함수로 만들고, 내부에서 $\text{await fetch()}$를 사용하여 데이터를 기다립니다.
import NewsList from '@/components/news-list';
// 1. async 키워드를 사용하여 서버 컴포넌트를 비동기로 정의
export default async function NewsPage() {
// 2. 컴포넌트 함수 내에서 직접 fetch 요청
const response = await fetch('http://localhost:8080/news');
// 3. 응답 상태 체크 및 에러 처리
if (!response.ok) {
// 에러 발생 시, throw를 통해 Next.js의 에러 경계(Error Boundary)로 전달
throw new Error('Failed to fetch news.');
}
// 4. 데이터 파싱 및 렌더링
const news = await response.json();
return (
<>
<h1>News Page</h1>
{/* 데이터가 준비될 때까지 기다리므로, undefined 체크가 필요 없음 */}
<NewsList news={news} />
</>
);
}
b. 클라이언트 코드 대비 주요 변경 사항
| 구분 | 이전 (클라이언트 측) | 현재 (서버 측) | 설명 |
| 디렉티브 | "use client"; | 제거 | 서버 컴포넌트로 전환됩니다. |
| 훅 | useState, useEffect 사용 | 제거 | 클라이언트 측 상태 및 부수 효과 관리가 필요 없습니다. |
| 조건부 JSX | if (news)로 데이터 체크 | 제거 | 서버 컴포넌트는 await 덕분에 데이터가 확실히 준비된 후 JSX가 렌더링되기에 데이터 체크 로직이 필요 없습니다. |
| 로딩/에러 | useState로 상태 관리 | throw new Error | 로딩은 데이터를 기다리는 동안 자동으로 처리되며, 에러는 throw로 던져 Next.js에 위임합니다. |
2. 서버 컴포넌트의 강력한 특징
전통적인 클라이언트 측 React 컴포넌트는 Promise를 반환할 수 없지만, React 서버 컴포넌트는 다릅니다.
- async/await 지원: Next.js 서버 컴포넌트 함수는 async 키워드를 사용하여 비동기 함수로 정의될 수 있습니다.
- 컴포넌트 내 직접 fetch: 데이터 요청을 useEffect나 useState 훅 없이 컴포넌트 함수 내부에 직접 작성할 수 있습니다.
서버 사이드에서는 JSX 조건문이 사라지는 이유
클라이언트 컴포넌트에서 useEffect를 사용했을 때는 JSX 내부에 if (news)와 같은 조건부 렌더링 로직이 필수였습니다. 이는 컴포넌트가 데이터를 가져오기 전에 news가 undefined인 상태 한 번 렌더링되면서 오류가 나는 것을 막기 위함이었습니다.
하지만, 서버 컴포넌트에서는 async/await를 사용합니다. 서버는 await 라인에서 데이터를 완전히 가져올 때까지 컴포넌트 실행을 일시 중지하고 기다립니다. await가 완료된 후에는 변수 news에 데이터가 이미 담겨 있음이 보장되므로, JSX 렌더링 시 불필요했던 조건부 로직을 제거하고 곧바로 컴포넌트를 렌더링할 수 있게 됩니다.
💡 장점: 왜 서버에서 데이터를 가져와야 하는가?
클라이언트 측 페칭과 달리, 서버 측 페칭은 다음과 같은 핵심 이점을 제공합니다.
- SEO (검색 엔진 최적화) 우위: 서버에서 페이지를 렌더링할 때 이미 데이터가 포함되어 있어, 검색 엔진 크롤러가 전체 내용을 쉽게 수집할 수 있습니다.
- 초기 로딩 성능 향상: 클라이언트가 JavaScript를 다운로드하고 실행한 후 다시 데이터를 요청하고 렌더링을 시작하는 과정을 없애, 사용자가 콘텐츠를 더 빠르게 볼 수 있습니다.
- 코드 간결성: useEffect, useState를 사용한 복잡한 상태 관리 코드를 제거할 수 있습니다.
3. 서버 렌더링의 검증: 페이지 소스 코드 차이
가장 핵심적인 변화는 최종 페이지가 렌더링되는 방식입니다.
- 클라이언트 측 페칭 결과: 브라우저에서 '페이지 소스 보기'를 했을 때, 실제 뉴스 헤드라인 등의 콘텐츠가 보이지 않습니다. 콘텐츠는 JavaScript가 실행된 후에야 동적으로 주입됩니다.
- 서버 측 페칭 결과: 서버에서 데이터를 가져와 HTML을 완성한 후 브라우저에 전송합니다. 따라서 '페이지 소스 보기'를 했을 때 뉴스 콘텐츠(예: 'Beaver' 관련 기사 제목)가 HTML 내부에 완전히 포함되어 있는 것을 확인할 수 있습니다.
이러한 특성 덕분에, 서버 컴포넌트에서 fetch를 직접 사용하는 방식이 Next.js에서 데이터를 가져오는 표준적이고 권장되는 접근 방식입니다.
'NextJS' 카테고리의 다른 글
| NextJS 로딩 상태 처리 (0) | 2025.10.20 |
|---|---|
| [NextJS] 서버 컴포넌트에서 DB 직접 접근 (0) | 2025.10.19 |
| [NextJS] 클라이언트 측에서 백엔드 API 데이터 가져오기 (feat. useEffect) (0) | 2025.10.18 |
| [NextJS] Pre-Renders(사전 랜더링) Page(페이지) (0) | 2024.04.20 |
| [NextJS] SQLite 데이터베이스 사용해보기 (0) | 2024.03.20 |