Next.js 클라이언트 컴포넌트가 서버에서 렌더링된다고요? 🤔 (App Router 파헤치기)

홍태극·2024년 4월 9일
0

Next.js 클라이언트 컴포넌트가 서버에서 렌더링된다고요? 🤔 (App Router 파헤치기)

안녕하세요! Next.js 13 버전부터 등장한 App Router, 다들 한번쯤 들어보셨거나 사용해보셨을 텐데요. 저도 처음 접했을 때 '서버 컴포넌트', '클라이언트 컴포넌트' 이런 용어들 때문에 살짝 머리가 아팠던 기억이 나요. 😅

특히 많은 분들이 "클라이언트 컴포넌트면 당연히 브라우저(클라이언트)에서만 돌아가는 거 아니야?" 라고 생각하시는데, "클라이언트 컴포넌트도 처음엔 서버에서 렌더링된다" 는 말을 들으면 "네? 그게 무슨 말이죠?" 하고 동공지진이 오기 쉽죠. 저도 그랬거든요!

그래서 오늘은 이 헷갈리는 부분! Next.js App Router 세상에서 클라이언트 컴포넌트가 어떻게 동작하는지, 정말 서버 사이드 렌더링(SSR)이 일어나는 건지, 그리고 이건 또 서버 컴포넌트랑 뭐가 다른 건지 속 시원하게 파헤쳐 보려고 해요!

🤔 App Router와 서버 컴포넌트, 기본부터 알아봐요

Next.js 13부터는 우리가 익숙했던 pages 폴더 대신 app 폴더가 메인이 되었어요. 이 app 폴더는 React가 새롭게 선보인 리액트 서버 컴포넌트(React Server Components, RSC) 라는 개념과 찰떡궁합으로 만들어졌답니다.

중요한 건, app 폴더 안에 만드는 컴포넌트는 기본적으로 모두 서버 컴포넌트로 취급된다는 거예요!

서버 컴포넌트가 뭐냐면요,

  • 말 그대로 서버에서만 렌더링되는 컴포넌트예요.

  • 렌더링 결과(HTML)만 클라이언트로 보내지고, 자바스크립트 코드는 클라이언트 번들에 포함되지 않아요. (이게 핵심!)

  • 덕분에 클라이언트가 다운로드해야 할 자바스크립트 양이 확 줄어서 초기 로딩 속도가 빨라져요! 🚀

  • 서버에서만 돌아가니까, 데이터베이스에 직접 접근하거나 비밀 키를 사용하는 등 서버 전용 작업도 안전하게 할 수 있죠.

  • 단점이라면, useState, useEffect 같은 React 훅이나 브라우저 이벤트 처리는 불가능하다는 거예요. 상태 변화나 사용자 인터랙션이 필요 없는 부분에 딱이죠.

😮 'use client' 붙였는데 서버 렌더링? 이게 무슨 일이죠?

자, 그럼 이제 오늘의 주인공, 클라이언트 컴포넌트 이야기를 해볼까요?

서버 컴포넌트에서는 상태 관리나 이벤트 처리를 못 한다고 했잖아요? 그럼 버튼 클릭이나 입력 폼 같은 인터랙티브한 UI는 어떻게 만드냐고요? 바로 이럴 때 클라이언트 컴포넌트를 사용해요.

어떤 컴포넌트를 클라이언트 컴포넌트로 만들고 싶으면, 아주 간단해요. 파일 맨 위에 딱 한 줄, 이 지시문을 추가해주면 돼요.

// 요렇게 파일 맨 위에!
"use client";

import React, { useState } from 'react';

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

  return (
    <div>
      <p>클릭 횟수 {count}</p>
      <button onClick={() => setCount(c => c + 1)}>증가!</button>
    </div>
  );
}

이렇게 "use client"; 를 붙이면 이제 이 컴포넌트는 useState, useEffect 같은 훅도 쓸 수 있고, 버튼 클릭 같은 이벤트도 처리할 수 있는 우리가 알던 그 리액트 컴포넌트처럼 동작해요.

그런데 여기서 진짜 신기한 점이 나와요! 🤯

"use client"; 를 붙여서 '이제 너는 클라이언트 컴포넌트야!' 라고 선언했지만, Next.js는 이 컴포넌트가 포함된 페이지를 맨 처음(최초) 접근할 때는 서버에서 한번 렌더링을 한다는 거예요!

"아니, 클라이언트 컴포넌트라면서요? 왜 서버에서 렌더링해요?" 싶으시죠? 과정을 한번 따라가 볼게요.

  1. 사용자가 페이지 요청
    사용자가 클라이언트 컴포넌트가 포함된 페이지를 딱! 요청해요.

  2. 서버 렌더링
    Next.js 서버는 요청받은 페이지 전체를 렌더링해요. 이때 "use client" 컴포넌트도 초기 상태 그대로 HTML로 그려버려요. (마치 스냅샷처럼요!)

  3. HTML 전송
    서버는 이렇게 만들어진 초기 HTML을 클라이언트(브라우저)로 보내줘요.

  4. 클라이언트 표시 & 하이드레이션 브라우저는 받은 HTML을 일단 화면에 빠르게 뿅! 보여줘요. 동시에 뒤에서는 다운로드한 자바스크립트 코드를 이용해서 이 정적인 HTML 위에 리액트 컴포넌트 기능을 입히는 하이드레이션(hydration) 작업을 해요. 하이드레이션이 끝나면 이제 버튼도 눌리고 상태도 변하는 진짜 인터랙티브한 컴포넌트가 되는 거죠!

즉, "use client" 컴포넌트는

  • 초기 로딩
    서버에서 첫 모습(HTML)을 그려서 빠르게 보여주고 (SSR 비슷하게)

  • 이후 동작
    클라이언트에서 자바스크립트가 활성화(하이드레이션)된 후에는 상태 변경이나 이벤트 처리를 전담하는 거예요.

이게 왜 좋냐면요, 사용자는 빈 화면 대신 의미 있는 첫 화면을 훨씬 빨리 볼 수 있고(초기 로딩 성능 개선!), 동시에 인터랙티브한 기능도 그대로 사용할 수 있게 되는 거죠. 우리가 예전에 알던 순수 CSR(Client-Side Rendering - 처음엔 빈 HTML 받고 자바스크립트로 전부 그림) 방식의 단점(느린 첫 화면 로딩)을 개선한 방식이라고 할 수 있어요.

🤔 서버 컴포넌트 vs 전통적인 SSR, 뭐가 다를까요?

여기까지 들으면 이런 질문이 생길 수 있어요. "어? 클라이언트 컴포넌트도 처음엔 서버에서 렌더링되면, 그냥 우리가 알던 SSR(getServerSideProps 같은 거)이랑 비슷한 거 아니에요? 그리고 서버 컴포넌트랑은 뭐가 다른 거죠?"

좋은 질문이에요! 서버 컴포넌트와 전통적인 SSR은 분명히 다른 점들이 있어요.

구분서버 컴포넌트 (RSC)전통적인 SSR (Pages Router 방식 예시)
기반 기술React Server Components (새로운 리액트 아키텍처)서버에서 리액트 컴포넌트를 HTML 문자열로 렌더링
결과물 형태특수한 스트리밍 포맷 (HTML + 플레이스홀더 등)완성된 HTML 문자열
클라이언트 JS포함 안 됨! (필요한 부분만 클라이언트 컴포넌트로)렌더링 + 하이드레이션 위한 JS 코드 포함 (번들 크기 커짐)
상태/이펙트사용 불가 (useState, useEffect 등 사용 X)사용 가능
주요 장점자바스크립트 번들 최소화, 초기 로딩 속도 극대화동적인 데이터에 따른 초기 렌더링, SEO
서버 부하컴포넌트 단위 캐싱 가능요청마다 전체 페이지 렌더링 (상대적으로 부하 클 수 있음)

핵심적인 차이는 서버 컴포넌트 자체가 클라이언트 자바스크립트 번들에 포함되지 않는다는 점이에요. 필요한 인터랙션은 별도의 "use client" 컴포넌트로 분리해서 로드하는 방식이죠. 그래서 초기 로딩 성능에 훨씬 유리해요.

반면, 전통적인 SSR은 페이지 전체를 서버에서 HTML로 만들지만, 그 페이지를 인터랙티브하게 만들기 위한 자바스크립트 코드(리액트 포함)는 여전히 클라이언트로 보내야 하죠.

Next.js App Router의 장점은 서버 컴포넌트와 클라이언트 컴포넌트를 자연스럽게 섞어 쓸 수 있다는 거예요. 정적인 부분은 서버 컴포넌트로 만들어 성능을 챙기고, 인터랙션이 필요한 부분만 클라이언트 컴포넌트로 만들어서 기능을 구현하는 거죠. 상황에 맞게 최적의 조합을 찾을 수 있다는 게 매력적이에요!

✨ 정리해볼까요?

휴~ 조금 복잡하게 느껴질 수도 있지만, 핵심만 다시 정리해 볼게요!

  • Next.js App Router의 컴포넌트는 기본적으로 서버 컴포넌트예요. (JS 번들 최소화, 성능 UP!)

  • 상태나 이벤트 처리가 필요하면 "use client" 를 붙여 클라이언트 컴포넌트로 만들어요.

  • 놀랍게도! 클라이언트 컴포넌트도 최초 접근 시에는 서버에서 한번 렌더링된 후(빠른 첫 화면!), 클라이언트에서 하이드레이션 과정을 거쳐 인터랙티브해져요.

  • 이 방식은 서버 컴포넌트(RSC) 와는 다르고, 전통적인 SSR과도 차이가 있어요. App Router는 두 방식의 장점을 조합해 사용할 수 있게 해주죠.

Next.js는 이런 새로운 접근 방식을 통해 개발자들이 더 빠르고 사용자 친화적인 웹 애플리케이션을 만들 수 있도록 계속 진화하고 있는 것 같아요. 처음엔 조금 낯설 수 있지만, 한번 익숙해지면 정말 강력한 도구가 될 거라고 생각해요!

혹시 App Router를 사용해보시면서 느낀 점이나 더 궁금한 점이 있다면 언제든지 댓글로 알려주세요! 같이 이야기 나누면서 배우면 더 좋잖아요? 😊

0개의 댓글