본문 바로가기
개발(Development)/Next.js 13

[Next.js 13] Server Component vs. Client Component 기본 및 사용 방법

by 카레유 2023. 8. 21.

# Server Component vs. Client Component 기본

Next.js 13에서는 Server Component와 Client Component를 개발자가 선택적으로 정의하여 사용할 수 있다.

이에 대한 기본적인 이해를 위해 렌더링부터 가볍게 정리해본다.


# 렌더링(Rendring)이란?

렌더링이란 결국 코드를 UI로 만드는 것을 의미한다.

따라서 React에서의 렌더링은 React Component를 HTML 로 만드는 과정이다.

 

# React 18 이전의 렌더링

1. CSR (Client Side Rendering)

React 18이 나오기 전,

리액트 컴포넌트의 모든 렌더링은 클라이언트(브라우저)에서 이루어졌다. 

 

- 서버는 React로 작성한 JS 코드 뭉텅이들을 브라우저에 응답하고,

- 브라우저는 응답받은 JS파일을 해석하여 HTML파일로 렌더링하고, 인터랙션이 필요한 코드들(이벤트 리스너 등)을 장착했다.

 

2. SSR(Server Side Rendering)

Next.js가 나오면서 아래와 같은 방식의 SSR을 쉽게 구현할 수 있게 되었다.

 

- NEXT.JS 를 통해 서버 단에서 1) 페이지별로 코드를 쪼갠 후(Code Split), 2) HTML을 렌더링한 다음, 3) 브라우저에 응답하면,

- 브라우저는 전달 받은 1) HTML을 노출하고, 2) 추가로 전달 받은 JS 코드들(이벤트 리스너 등)을  결합하는 Hydration 과정을 거친다.

 

cf. Hydration: 뼈대 뿐인 HTML에 JS코드를 결합시켜 인터랙션(클릭 이벤트 처리 등)을 장착하는 과정이다.

 

하지만 이 때에도 기본적으로는  브라우저에서 렌더링 되는 CSR이 기본이었으며,

서버에서 렌더링되는 SSR을 적용하려면, getServersideProps 등의 추가적인 코드 작성 및 설정이 필요했다.

 

# React 18 이후의 렌더링

React 18부터 Server Component가 도입되었고, Next.js 13은 이를 완벽하게 지원한다.

이에 따라 Next.js 13 부터는 아래의 두가지 형식으로 컴포넌트를 만들 수 있다.

 

  • Server Component
    • 서버에서 HTML을 렌더링하여 브라우저에 응답한다.
    • Hydration 과정은 없다.
  • Client Component
    • 서버에서 기본적인 HTML은 렌더딩하여 브라우저에 응답한다.
    • Hydration(JS Interactivity)만 브라우저에서 이루어진다.

 

기본적인 HTML자체는 모두 서버에서 렌더링된다.

단, Client Component의 경우에만 브라우저에서 Hydaration 과정이 진행된다.

 

Event Listener(클릭 이벤트 등), Browser API(web storage 등), React Hooks(useState, useEffect 등) 등은 브라우저에서만 작동하는 클라이언트 단 JS코드이며, 브라우저에서 Hydration 과정을 거치는 Client Component에서만 정의될 수 있다.

 

따라서, Server Component에서는 사용이 불가하다.


# Server Component와 Client Component 정의 방법 및 특징

# Server Component 

Next.js에서는 /app 디렉터리 내부에 컴포넌트를 만들면, 디폴트로 Server Component가 된다.

따라서 Server Component로 만들기 위해 별도의 작업을 할 필요가 없다.

 

export default function Home(){
  return (
    <main>
      <h1>Home: Server Component</h1>
    </main>
  );
}

 

  • 모든 컴포넌트는 Server Component가 디폴트.
  • 서버 단에서 렌더링 되므로, 브라우저 환경의 코드는 사용 불가:
    • Event Listener(onClick 등) 사용 불가
    • React Hooks(useState 등) 사용 불가
    • Browser API(webStorage 등) 사용 불가
  • Server Component는 Client Compoent 포함 가능(반대는 불가)
  • Server Component는 async 함수로 정의 가능
    • 따라서 컴포넌트 내부에서 바로 await fetch() 호출이 가능하다.
export default async function Home() {
  const res = await fetch("https://jsonplaceholder.typicode.com/todos/1");
  const data = await res.json();

  return (
    <main>
      <h1>Home</h1>
      <p>{data.title}</p>
    </main>
  );
}

 

Server Component는 서버에서 렌더링 되므로, 아래와 같은 장점이 있다.

 

  • 불필요한 dependency를 클라이언트에 전송할 필요가 없고,
  • Database 접근 및 fetch 속도가 개선될 수 있으며,
  • 보안 정보도 좀더 안전하게 관리할 수 있다.

 

# Client Component 

Client Component를 정의하기 위해서는 컴포넌트 파일 최상단에 "use client"를 추가해 주면 된다.

 

"use client";

import { useState } from "react";

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

  return (
    <div>
      <p>You clicked {count} times</p>
      <button onClick={() => setCount((prev) => prev + 1)}>Click me</button>
    </div>
  );
}

 

  • 컴포넌트 파일 최상단에 "use client"를 붙여주면 Client Component가 된다.
  • 클라이언트(브라우저) 단에서 렌더링 되므로, 브라우저 환경의 코드 사용 가능:
    • Event Listener(onClick 등) 사용 가능
    • React Hooks(useState 등) 사용 가능
    • Browser API(webStorage 등) 사용 가능
  • Client Component에 내부에 포함되는 자식 컴포넌트들도 모두 자동으로 Client Component가 된다.
  • Client Componemt는 Server Component를 포함할 수 없다. (반대만 가능)

 

# Server Component 와 Client Component의 사용 및 배치 방법

기본적으로 모든 컴포넌트를 Server Component로 만들고,

클라이언트 단의 유저 인터랙션 처리나 React hooks 사용이 필요할 때만 Client Component를 추가해주면 좋다.

 

1. Client Component 사용이 필요할 때:

  • 인터랙티비티 및 Event Listener 사용이 필요할 때
  • React Hooks (useState, useEffect 등) 사용이 필요할 때
  • Browser 단의 API (web storage 등) 사용이 필요할 때

2. Server Component 사용이 필요할 때:

  • 위의 Client Component 사용이 불가피한 경우를 제외한 모든 경우!

 

공식 문서에서는 특히 아래의 경우 Server Component를 사용할 것을 권고한다.

  • Fetch data
  • Access Backend Resources(directly)
  • Keep sensitive information on the server (access tokens, API keys, etc)
  • Keep large dependencies on the server / Reduce client-side JavaScript

 

아래 웹페이지를 보면, 대부분의 컴포넌트가 유저 인터랙션이 필요 없는 영역임을 알 수 있다.

 

출처: Next.js 공식 문서

 

  • Navbar, Sidebar, Main 컴포넌트:
    • 컨텐츠 및 단순 링크(a태그) 등을 담는 컨테이너일 뿐이다.
    • 유저 인터랙션은 없거나 불필요하다.
    • Server Component로 정의한다.
  • Search, Button 컴포넌트:
    • 검색창 입력, 버튼 클릭 정도만 유저 인터랙션이 발생하는 영역이다.
    • change, click 이벤트 처리 및 useState등의 React Hook이 필요하다.
    • Client Component로 정의한다.

 

따라서, Navbar, Sidebar, Main컴포넌트는 Server Component로 정의하고,

Search, Button 컴포넌트는 Client Component로 정의하여 Main 안에 포함시키면 된다.

Server Component는 Client Component를 포함할 수 있기 때문이다.

 

 

 

 

댓글