Next.js 서버 컴포넌트 vs 클라이언트 컴포넌트 (+ 서버 사이드 렌더링)

2025. 9. 1. 18:47·프론트엔드/React

서론

Next.js를 사용하면서 렌더링 방식 


1. 컴포넌트의 실행 위치: 서버 컴포넌트 vs 클라이언트 컴포넌트

가장 먼저 알아야 할 것은 컴포넌트가 어디서 실행되느냐이며, Next.js는 컴포넌트를 실행하는 위치에 따라 두 가지 종류로 로 나눔

1-1. 서버 컴포넌트 (Server Components)

Next.js의 기본값. 별도의 선언이 없으면 모든 컴포넌트는 서버 컴포넌트로 동작

  • 실행 위치: 오직 서버에서만 실행
  • 주요 특징:
    • 번들 크기: 클라이언트로 전송되지 않으므로 자바스크립트 번들에 포함되지 않아 번들 크기를 줄여줌
    • 데이터 접근: 서버 자원(파일 시스템, 데이터베이스, 환경 변수)에 직접 접근하여 데이를 가져올 수 있음
    • 인터랙션 불가: `useState`, `useEffect` 등 클라이언트 측 훅을 사용할 수 없으며, `onClick`과 같은 이벤트 핸들러도 지원하지 않음

1-2. 클라이언트 컴포넌트 (Client Components)

사용자 상호작용이 필요한 컴포넌트

    • 선언 방법: 파일 최상단에 `'use client'` 지시어를 선언
    • 실행 위치: 서버에서 한번 렌더링된 후, 클라이언트(브라우저)에서 다시 실행
    • 주요 특징:
      • 번들 크기: 클라이언트로 전송되므로 자바스크립트 번들에 포함
      • 데이터 접근: API 엔드포인트에 HTTP 요청을 보내 데이터를 가져와야 하고, 서버 자원에 직접 접근할 수 없음
      • 인터랙션 가능: `useState`, `useEffect`, `onClick` 등 모든 클라이언트 측 기능을 사용할 수 있음
      • 바운더리:
        • `'use client'` 지시어는 단순히 해당 컴포넌트를 클라이언트 컴포넌트로 만드는 것을 넘어, 서버와 클라이언트 코드를 구분하는 경계선 역할을 함
        • `'use client'`가 선언된 파일과 그 하위에서 `import`되는 모든 컴포넌트들은 클라이언트 번들에 포함
        • 따라서, 불필요하게 여러 파일에 `'use client'`를 중복해서 선언할 필요가 없음
        • 서버 컴포넌트 안에 클라이언트 컴포넌트가 있는 경우, 해당 클라이언트 컴포넌트가 바로 서버와 클라이언트의 경계가 됨

https://nextjs.org/docs/app/getting-started/server-and-client-components

 

Getting Started: Server and Client Components | Next.js

Learn how you can use React Server and Client Components to render parts of your application on the server or the client.

nextjs.org


2. 렌더링 방식 : SSR vs CSR

페이지를 렌더링하는 방식에는 크게 SSR과 CSR이 존재

2-1. SSR (Server-Side Rendering)

SSR은 서버에서 완성된 HTML을 만들어 클라이언트에 보내는 방식

  • 동작 방식: 사용자가 페이지를 요청하면, 서버에서 컴포넌트들을 렌더링해 HTML 파일을 완성. 이 HTML 파일을 클라이언트에 보내면 브라우저는 즉시 화면에 내용을 표시
  • 장점: 초기 로딩이 매우 빠르며, 검색 엔진 봇이 완성된 HTML을 읽을 수 있어 SEO(검색 엔진 최적화)에 유리

2-2. CSR (Client-Side Rendering)

CSR은 서버에서 빈 HTML 뼈대만 받고, 클라이언트가 모든 내용을 동적으로 채우는 방식

  • 동작 방식: 서버는 빈 HTML 파일과 자바스크립트 번들을 전송. 클라이언트에서 자바스크립트 코드를 실행해 데이터를 가져오고 DOM을 구성
  • 장점: 페이지 전환이 빠르고, 서버 부하가 적음

3. 하이드레이션과 RSC 페이로드

Next.js는 위의 개념을 결합하여 효율적인 렌더링을 구현

3-1. 하이드레이션 (Hydration)

하이드레이션은 서버에서 렌더링된 정적인 HTML에 클라이언트 측 기능을 연결하는 과정

  • 원리: Next.js는 초기 페이지 로드 시, 서버 컴포넌트와 클라이언트 컴포넌트를 모두 서버에서 렌더링하여 HTML을 생성. 이 생성된 HTML이 클라이언트에 도착하면 사용자는 즉시 콘텐츠를 볼 수 있음
  • 동작: 이후 클라이언트 컴포넌트의 자바스크립트 코드가 로드되면, React는 이 코드를 HTML과 일치시켜 `onClick`과 같은 이벤트 핸들러를 붙여줌. 이 과정을 통해 정적인 HTML이 동적으로 변함

결론: 클라이언트 컴포넌트는 서버에서 HTML로 미리 렌더링된 후, 클라이언트 측에서 하이드레이션 과정을 거쳐 상호작용이 가능해짐. 서버 컴포넌트는 상호작용이 없어 하이드레이션이 필요하지 않음

3-2. RSC 페이로드 (React Server Components Payload)

RSC 페이로드는 서버 컴포넌트의 렌더링 결과를 담은 특별한 데이터 형식

  • 역할: RSC 페이로드는 완성된 HTML이 아니라, 변경이 필요한 부분만 전송하는 역할을 합니다.
  • 장점: 페이지 전체를 다시 로드하는 대신, 변경된 서버 컴포넌트의 데이터만 페이로드로 전송하여 클라이언트 측에서 효율적으로 업데이트가 가능. 이는 CSR의 장점인 빠른 업데이트와 유사함

4. 간단한 예시 및 동작과정 (상품 목록 및 좋아요)

4-1. `ProductPage.jsx` : 서버 컴포넌트

서버에서 상품 데이터를 가져와 페이지의 기본 구조를 생성

import LikeButton from './LikeButton'; // 클라이언트 컴포넌트를 가져옵니다.

// 이 함수는 서버에서 실행되어 데이터를 가져옵니다.
async function getProduct() {
  const res = await fetch('https://api.example.com/product/123');
  return res.json();
}

export default async function ProductPage() {
  const product = await getProduct();
  
  return (
    <div>
      <h1>{product.name}</h1>
      <p>{product.description}</p>
      {/* 클라이언트 컴포넌트를 서버 컴포넌트 안에 둡니다. */}
      <LikeButton initialLikeCount={product.likes} />
    </div>
  );
}

4-2. `LikeButton.jsx` : 클라이언트 컴포넌트

`useState`를 사용하여 '좋아요' 상태를 관리하고, 버튼 클릭을 처리

'use client';

import { useState } from 'react';

export default function LikeButton({ initialLikeCount }) {
  const [likeCount, setLikeCount] = useState(initialLikeCount);
  
  const handleClick = async () => {
    const newCount = likeCount + 1;
    setLikeCount(newCount);

    await fetch('/api/like', { method: 'POST' });
  };

  return (
    <button onClick={handleClick}>
      좋아요: {likeCount}
    </button>
  );
}

 

4-3. 동작 과정

  1. 초기 로딩 (SSR과 하이드레이션)
    • 사용자가 페이지를 요청하면, 서버가 `ProductPage` 서버 컴포넌트와 `LikeButton` 클라이언트 컴포넌트를 모두 렌더링하여 완성된 HTML을 생성
    • 브라우저는 이 HTML을 즉시 화면에 표시. 이때 '좋아요' 버튼은 정적인 상태로, 사용자 상호작용이 없음
    • 이어서 `LikeButton.jsx`의 자바스크립트 코드가 다운로드되고, React가 HTML의 버튼을 찾아 하이드레이션을 수행. 이 과정을 통해 버튼에 클릭 이벤트가 연결되고, `useState` 같은 기능이 활성화 됨
  2. 사용자 상호작용 (RSC 페이로드)
    • 사용자가 '좋아요' 버튼을 클릭하면 `handleClick` 함수가 클라이언트에서 실행
    • 클라이언트가 서버에 '좋아요' 요청을 보내면, 서버는 데이터베이스의 '좋아요' 수를 업데이트
    • 만약 페이지를 새로고침하거나 데이터가 변경될 때, 서버는 `ProductPage`를 다시 렌더링
      • 이때 Next.js는 전체 HTML이 아니라, 변경된 '좋아요' 수 정보가 담긴 RSC 페이로드만 클라이언트에 보냄
    • 클라이언트는 이 페이로드를 받아 페이지 전체를 다시 그리는 대신, 변경이 필요한 부분(좋아요 수)만 업데이트

최종 결론 및 요약

'프론트엔드 > React' 카테고리의 다른 글

TodoList 만들기 - 성능 개선 (1)  (0) 2025.12.17
TodoList 만들기  (0) 2025.12.17
Hook의 규칙 (최상위에서 Hook을 호출해야 하는 이유)  (0) 2025.12.08
React Compiler v1.0 알아보기 (useMemo, useCallback, React.memo)  (0) 2025.11.05
모든 웹 개발자가 관심을 가져야 할 핵심 웹 지표 [리액트 딥다이브 12장]  (0) 2025.09.09
'프론트엔드/React' 카테고리의 다른 글
  • TodoList 만들기
  • Hook의 규칙 (최상위에서 Hook을 호출해야 하는 이유)
  • React Compiler v1.0 알아보기 (useMemo, useCallback, React.memo)
  • 모든 웹 개발자가 관심을 가져야 할 핵심 웹 지표 [리액트 딥다이브 12장]
의현
의현
개발하는 하루
  • 의현
    UIHYEON
    의현
  • 링크

    • 김의현 포트폴리오
    • GitHub
    • LinkedIn
  • 전체
    오늘
    어제
    • 분류 전체보기 (240) N
      • 프론트엔드 (65)
        • JavaScript (52)
        • HTML (3)
        • React (7)
        • CSS (2)
        • CS (1)
      • 프로젝트 (21)
        • Portfolio 사이트 개발 (21)
      • 코딩테스트 (150) N
        • Binary Search (2)
        • bfs (Breadth-first s.. (4)
        • dfs (Deapth-first se.. (1)
        • Greedy (1)
        • Dynamic Programming (1)
        • two pointer (4)
        • 구현 (2)
        • LIS(Longest Increasi.. (0)
        • 문자열 (3)
        • 자료구조 (6)
        • 비트마스크 (2)
        • 수학 (2)
        • 프로그래머스 (65)
        • LeetCode (57) N
      • 자격증 (1)
  • 인기 글

  • 최근 댓글

  • 최근 글

  • hELLO· Designed By정상우.v4.10.3
의현
Next.js 서버 컴포넌트 vs 클라이언트 컴포넌트 (+ 서버 사이드 렌더링)
상단으로

티스토리툴바