다다의 개발일지 6v6

[Next.js] 백엔드 설정하기, 서버 vs 클라이언트 컴포넌트 차이점 본문

Frontend/Next.js

[Next.js] 백엔드 설정하기, 서버 vs 클라이언트 컴포넌트 차이점

dev6v6 2025. 3. 9. 01:42

Nextjs API 서버 구축 ( json-server )  

db.json 파일을 만들고 아래 코드를 터미널에 치면 된다~

--watch는 변경될때마다 새로고침 해준다.

npx json-server --port 9999 --watch db.json

 

 

Next.js의 컴포넌트 : 서버, 클라이언트 (이건 react 최신 버전에도 있다고 함)

특별한 처리를 해주지 않으면 서버 컴포넌트(기본)로 간주한다.

클라이언트 컴포넌트 처리: 컴포넌트 파일 맨 위에 "use client";

각각 사용할 수 있는 api가 다르다.
s가 서버, c가 클라이언트 -> 사용자와 상호작용이 필요한 걸 클라이언트 컴포넌트로 만들면 됨.

 

서버, 클라이언트 컴포넌트에 대해서 더 상세히 알아보자.

이 두 컴포넌트를 도입하여 성능과 개발 경험을 최적화할 수 있다.

 

  • 서버 컴포넌트: 백엔드에서 렌더링되고 클라이언트로 HTML만 전달됨 → SEO 최적화, 빠른 로딩, 서버 자원 활용
  • 클라이언트 컴포넌트: 브라우저에서 실행되며 상호작용 가능 → 상태 관리, 이벤트 핸들링, useState, useEffect 등 사용 가능

 

1. 서버 컴포넌트란?

📌 서버에서 실행되는 React 컴포넌트로, Next.js의 기본 설정이다.

 

특징

서버에서 렌더링 → 브라우저에는 HTML만 전달
데이터베이스 및 API 호출 가능 (서버에서 직접 실행됨)

   -> 클라이언트에서 호출하는 거랑 뭐가 다를까? 

2025.03.15 - [Frontend/Next.js] - [Next.js] 서버 vs 클라이언트 컴포넌트에서 - fetch, axios로 API 호출 차이점

 

[Next.js] 서버 vs 클라이언트 컴포넌트에서 - fetch, axios로 API 호출 차이점

클라이언트에서 fetch 요청 vs 서버에서 fetch 요청Next.js에서는 fetch()를 클라이언트와 서버에서 모두 사용할 수 있음. 하지만 실행되는 환경이 다르기 때문에 성능과 보안 측면에서 차이가 있음. 

dev6v6.tistory.com

 

 네트워크 요청(API, DB 쿼리) 최적화 가능
 useState, useEffect, useRef 같은 클라이언트 훅 사용 불가
 렌더링 결과만 클라이언트에 전달되므로 JS 번들 크기가 줄어듦 → 성능 최적화

 

서버 컴포넌트 예제 (기본 설정)

// app/components/UserList.tsx (서버 컴포넌트)
import React from "react";

async function getUsers() {
  const res = await fetch("https://jsonplaceholder.typicode.com/users"); // 서버에서 API 요청
  const users = await res.json();
  return users;
}

export default async function UserList() {
  const users = await getUsers(); // API 요청 후 데이터 가져오기
  return (
    <ul>
      {users.map((user: any) => (
        <li key={user.id}>{user.name}</li>
      ))}
    </ul>
  );
}

 

특징:

  • fetch()를 서버에서 실행하기 때문에 클라이언트에서는 API 요청 부담이 없음
  • 클라이언트는 HTML 결과만 전달받음
  • React의 useEffect, useState 등을 사용할 필요 없음

 

2. 클라이언트 컴포넌트란?

📌 브라우저에서 실행되는 React 컴포넌트.
👉 상호작용(이벤트, 상태 변경 등)이 필요한 경우 클라이언트 컴포넌트를 사용해야 함

 

특징

useState, useEffect, useRef 등 리액트 훅 사용 가능
버튼 클릭, 폼 입력 등 이벤트 핸들링 가능
서버 요청은 fetch()를 클라이언트에서 실행해야 함 (CSR 방식)
JavaScript 번들이 클라이언트로 전달됨 → 초기 로딩이 상대적으로 느릴 수 있음

 

 

클라이언트 컴포넌트 예제

"use client"; // 클라이언트 컴포넌트로 설정

import React, { useState, useEffect } from "react";

export default function Counter() {
  const [count, setCount] = useState(0);

  return (
    <div>
      <p>현재 카운트: {count}</p>
      <button onClick={() => setCount(count + 1)}>+</button>
      <button onClick={() => setCount(count - 1)}>-</button>
    </div>
  );
}

 

특징:

  • "use client"; 선언이 필요함
  • useState를 이용해 상태 관리 가능
  • 버튼 클릭 시 상태 변경 가능
  • JavaScript 번들이 클라이언트로 전달되어야 함

 

3. 서버 컴포넌트 vs 클라이언트 컴포넌트 비교

  서버 컴포넌트 클라이언트 컴포넌트
실행 위치 서버에서 실행 브라우저에서 실행
데이터 요청 서버에서 직접 요청 (API, DB) 클라이언트에서 fetch 요청
React 훅 사용 ❌ 사용 불가 ✅ useState, useEffect 사용 가능
상호작용 (이벤트) ❌ 불가능 ✅ 가능 (버튼 클릭, 폼 입력 등)
초기 로딩 속도 ✅ 빠름 (JS 번들 최소화) ❌ 느릴 수 있음 (JS 번들 포함)
SEO 최적화 ✅ 가능 (HTML만 렌더링) ❌ 불리 (CSR 방식)
번들 크기 ✅ 작음 ❌ 큼 (JS 포함)

 

4. 서버 컴포넌트와 클라이언트 컴포넌트 함께 사용하기

 

대부분의 Next.js 애플리케이션에서는 서버 컴포넌트와 클라이언트 컴포넌트를 혼합해서 사용한다.

📌 예제: 서버 컴포넌트에서 데이터를 가져오고, 클라이언트 컴포넌트에서 상호작용

 

서버 컴포넌트 (데이터 가져오기)

// app/components/UserList.tsx (서버 컴포넌트)
import Counter from "./Counter"; // 클라이언트 컴포넌트 가져오기

async function getUsers() {
  const res = await fetch("https://jsonplaceholder.typicode.com/users");
  const users = await res.json();
  return users;
}

export default async function UserList() {
  const users = await getUsers();

  return (
    <div>
      <h2>사용자 목록</h2>
      <ul>
        {users.map((user: any) => (
          <li key={user.id}>{user.name}</li>
        ))}
      </ul>
      <Counter /> {/* 클라이언트 컴포넌트 사용 */}
    </div>
  );
}

 

클라이언트 컴포넌트 (상호작용)

// app/components/Counter.tsx (클라이언트 컴포넌트)
"use client";

import { useState } from "react";

export default function Counter() {
  const [count, setCount] = useState(0);

  return (
    <div>
      <p>카운트: {count}</p>
      <button onClick={() => setCount(count + 1)}>+</button>
      <button onClick={() => setCount(count - 1)}>-</button>
    </div>
  );
}

 

설명:

  1. UserList.tsx(서버 컴포넌트)에서 API 요청을 서버에서 실행 → 클라이언트 부담이 줄어듦
  2. Counter.tsx(클라이언트 컴포넌트)에서 useState를 이용해 버튼 클릭 이벤트 처리

 

5. 언제 서버 컴포넌트 vs 클라이언트 컴포넌트를 사용할까?

서버 컴포넌트 사용하면 좋은 경우

  • 데이터베이스 연결 및 API 요청이 필요한 경우
  • SEO 최적화가 중요한 경우 (검색 엔진 노출)
  • 빠른 페이지 로딩이 필요한 경우
  • Next.js의 fetch() 최적화를 활용하고 싶을 때

클라이언트 컴포넌트 사용하면 좋은 경우

  • 버튼 클릭, 폼 입력 등 사용자 인터랙션이 필요한 경우
  • useState, useEffect, useRef 같은 React 훅을 사용해야 하는 경우
  • 클라이언트에서 실시간 데이터 업데이트(WebSocket, Polling)

 

6. 정리

✔ Next.js의 기본 컴포넌트는 서버 컴포넌트
서버 컴포넌트데이터 요청 및 렌더링 최적화
클라이언트 컴포넌트상호작용과 상태 관리 가능
둘을 함께 조합하여 최적의 성능과 사용자 경험 제공