NextJS 13버전부터는 서버 컴포넌트와 클라이언트 컴포넌트 두 가지 개념을 통해 렌더링 방식을 규정했다.
일단 기본적으로 서버 컴포넌트와 클라이언트 컴포넌트가 무엇인지 이해해보자.
server component
서버 컴포넌트는 서버에서만 실행되고 렌더링 되는 React의 컴포넌트이다.
여기서 말하는 서버 는 애플리케이션이 실행되는 NodeJS 등의 런타임 환경을 의미한다.
서버 컴포넌트는 애플리케이션의 일부 UI를 서버에서 처리하고 완성된 HTML을 브라우저에 전달해준다. 이 방식 덕분에 브라우저에서는 별도의 자바스크립트 실행 없이 즉시 화면을 볼 수 있으며, 서버 측에서 데이터 패칭 및 비즈니스 로직이 모두 처리된 상태의 최종 결과물만 전송된다는 점이 특징이다. 이를 통해 다음과 같은 장점이 있다:
- 번들 크기 최소화: 서버 컴포넌트의 자바스크립트 코드는 브라우저로 전달되지 않아, 네트워크 트래픽과 클라이언트 리소스 낭비를 줄인다.
- 초기 렌더링 속도 향상: HTML만 받아 브라우저가 빠르게 내용을 표시할 수 있으므로, 느린 네트워크나 저사양 기기에서도 빠른 첫 화면 노출이 가능하다.
- 보안성 강화: 환경 변수, 데이터베이스, 민감한 내부 로직 등은 서버에서만 접근·처리되며, 클라이언트에는 절대 노출되지 않는다.
- SEO에 유리: 이미 렌더링된 HTML이 제공되기 때문에, 검색 엔진이나 크롤링 봇이 페이지 정보를 쉽게 파악할 수 있다.
추가적으로 서버 컴포넌트에서 발생하는 백엔드 API요청에 있어서 CORS 에러가 발생하지 않는다. CORS 정책은 브라우저에서 다른 도메인에 네트워크 요청을 할 경우에 적용되기 때문에, 서버와 서버 간의 통신에서는 적용되지 않는다.
client component
클라이언트 컴포넌트는 브라우저(클라이언트)에서 실행되고 렌더링되는 React의 컴포넌트이다. 여기서 말하는 클라이언트는 사용자의 웹 브라우저 환경을 의미하며, Next.js에서는 해당 컴포넌트 파일의 최상단에 "use client" 지시어를 선언하여 지정한다.
클라이언트 컴포넌트는 애플리케이션의 일부 UI를 브라우저에서 동적으로 처리하며, 그 동작 방식과 특징은 다음과 같다:
- 상호작용 중심:
- 버튼 클릭, 입력 폼, 모달 등 사용자의 실시간 입력이나 이벤트에 반응하는 UI를 담당한다.
- JS 번들 전달 필수:
- 클라이언트 컴포넌트의 자바스크립트 코드는 번들로 패키징되어 브라우저로 전송된다. 이 덕분에 상태 관리(useState), 생명주기 처리(useEffect), 이벤트 핸들러 등 React의 모든 브라우저 기반 기능을 사용할 수 있다.
- 브라우저 API 접근 가능:
- window, localStorage 등 브라우저 전용 API를 자유롭게 활용할 수 있다.
NextJS에서 서버 컴포넌트 개념을 사용한다고 완전한 SSR 방식인 것은 아니다.
서버 컴포넌트 와 클라이언트 컴포넌트 를 사용한 방식은 SSR 방식과는 차이가 있는데, 크게 랜더링 범위와 JS번들 전달 구조에 있다.
- SSR:
- 전체 페이지의 UI를 서버에서 렌더링 후 완성된 HTML을 브라우저에 전달한다.
- 클라이언트에게 전체 JS 번들을 전달하고, 클라이언트에서는 이를 통해 페이지에 상호작용이 가능케 하는 하이드레이션(Hydration)을 진행한다.
- 서버 + 클라이언트 컴포넌트:
- 서버 컴포넌트
- 상호 작용이나 브라우저 기능이 필요 없는 UI로 구성된 컴포넌트만 렌더링 후 완성된 HTML을 브라우저에게 전달한다.
- JS 번들의 전달이 필요하지 않은 UI로 구성되어 있기에 HTML 전달 직후 역할은 끝이 난다.
- 클라이언트 컴포넌트
- 상호 작용이나 브라우저 기능이 필요한 UI로 구성된 컴포넌트이다.
- 필요한 JS 번들을 전달 받아 하이드레이션한다.
- 서버 컴포넌트
즉, SSR 방식과 다르게 역할에 맞게 부분적으로 영역을 분리하여 처리하기 때문에, JS 번들 패키징 및 전달을 최소화하고 Hydration 지연 최소화 등의 이점을 가질 수 있다.
여기서 서버 컴포넌트 와 클라이언트 컴포넌트 의 혼합 렌더링 방식을 왜 사용하게 됐는지 이해할 수 있다.
SSR 방식을 사용하는 가장 큰 이유가 빠른 초기 로딩 속도이다. 초기 로딩 속도가 빠르면 얻을 수 있는 이점이 SEO 개선과 빈 화면으로 인한 사용자 이탈 최소화이다. 그런데 여기서 문제는 JS 번들 크기와 Hydration 지연이다.
Hydration 지연 최소화는 클라이언트 컴포넌트에서 필요한 부분에만 적용하기 때문에 필요하지만, JS 번들 크기는 복합적인 이유로 반드시 최적화 하여야 한다.
JS 번들 크기가 중요한 이유는 두 가지 정도가 있다.
첫 번째로 초기 로딩 속도에 영향을 준다. 번들의 크기가 증가할 수록 브라우저가 더 많은 데이터를 다운로드 해야 한다. 네트워크 속도가 느려질 수록 영향이 커지기 때문에, 반드시 번들의 크기를 최소화해야 SSR 혹은 혼합 렌더링 방식을 선택한 이유를 극대화 할 수 있다.
두 번째로 JS 번들을 전달하기 위한 트래픽 비용이 발생하기 때문이다. SSR방식에서는 HTML을 생성하고 이에 해당하는 전체 JS코드를 번들로 전달하는 반면, 혼합 방식에서는 클라이언트 컴포넌트에 해당하는 부분만 번들로 전달하게 된다. 동적인 React 앱 동작을 위해서 SSR에서는 전체를 전달하는데, 혼합 방식에서는 동적인 React 앱 동작을 위한 컴포넌트를 클라이언트 컴포넌트로 분리해놓았기 때문에 가능한 경우이다. 즉, 전달해야하는 JS번들이 최소화 되기 때문에 서버 트래픽 비용을 줄일 수 있다는 이점이 있다.
이러한 이유로 NextJS 이용해 웹을 제작하게 된다면 서버 컴포넌트 중심의 개발을 지향해야한다. 서버 컴포넌트를 기본으로 하며, 상호작용이 필요한 구간을 가장 작은 단위로 나눠 클라이언트 컴포넌트 로 구현해야한다. 또한, 클라이언트 컴포넌트의 JS 번들 최소화를 위해 코드 스플리팅을 하는 것도 고려하는 것이 좋다.
'React' 카테고리의 다른 글
[React] 가상화, react-virtualized (0) | 2025.07.25 |
---|---|
[React] 메모이제이션 / useMemo(), useCallback(), React.memo에 대하여 (0) | 2025.07.25 |
[React] Zustand (0) | 2025.07.02 |
[React] Tailwind CSS (0) | 2025.06.04 |
[React] Recoil (0) | 2025.05.23 |