기술 학습/NextJS

[Next.js] SSR + CSR 사용 방법

현인(Hyeon In) 2025. 2. 3. 17:32

Next.js는 기본적으로 서버 사이드 렌더링(SSR)을 지원한다. 하지만 개발을 하다 보면 간혹 클라이언트 사이드 렌더링(CSR)이 필요한 경우가 생긴다. Next.js는 이러한 경우에도 대처할 수 있도록 CSR 기능도 제공한다. 다시 말해, SSR + CSR 구조로 페이지가 만들어 질 수 있다는 뜻이다.

사용 방법

사용 방법은 간단한데, ‘use client’ 구문을 컴포넌트 구현 코드 최상단에 선언하면 된다. Next.js 서버에서는 해당 컴포넌트를 CSR 컴포넌트로 해석하여 서버에서 렌더링을 하지 않고 클라이언트로 렌더링을 넘긴다. 아래 코드를 보자.

'use client'
 
import { useState } from 'react'
 
export default function Counter() {
  const [count, setCount] = useState(0)
 
  return (
    <div>
      <p>Count: {count}</p>
      <button onClick={() => setCount(count + 1)}>Increment</button>
    </div>
  )
}

앞서 언급한 것처럼, 'use client' 구문을 최상단에 선언하였기에 Counter 컴포넌트는 CSR 컴포넌트가 된다.

import Header from './header'
import Counter from './counter' // 클라이언트 컴포넌트
 
export default function Page() {
  return (
    <div>
      <Header />
      <Counter />
    </div>
  )
}

위 페이지에서 Counter 컴포넌트를 사용하고 있는데, Counter 부분을 제외한 나머지 부분(div, Header)은 서버에서 그려지며 Counter 컴포넌트는 클라이언트에서 마저 그려진다.

개인적인 궁금점들

기본적인 사용 방법은 위와 같고, 개발을 하면서 고민했던 부분들을 조금 더 정리해 보려고 한다.

1. CSR 컴포넌트 내부에 SSR 컴포넌트가 사용되면 클라이언트에서 렌더링이 될까?

그렇다. ‘use client’가 선언된 컴포넌트를 기준으로 모든 하위 컴포넌트는 클라이언트에서 렌더링된다.

2. CSR 컴포넌트 하위에 위치한 모든 컴포넌트들은 별도로 ‘use client’를 선언하지 않아도 될까?

대부분의 경우에는 선언하지 않아도 되지만, 선언이 필요한 경우도 있다. A라는 클라이언트 컴포넌트 하위에 위치한 B라는 컴포넌트가 있다고 가정해보자. B가 클라이언트 렌더링이 필요한 컴포넌트라고 할 때, A에서만 사용이 된다면 별도로 use client를 선언하지 않아도 되지만, 서버 컴포넌트에서도 호출이 된다면? 예를 들어 C라는 서버 컴포넌트가 있을 때, C에서 B를 사용할 경우 B는 ‘use client’ 선언이 빠져있다면 서버 컴포넌트로 해석될 것이다. 이럴 때에는 ‘use client’를 호출해 줘야 한다. 아래 표를 보면 이해에 도움이 될 것 같다.

use client가 선언된 부모 내부에서만 사용하는 컴포넌트 ❌ 필요 없음 부모가 클라이언트 컴포넌트면, 하위 컴포넌트도 자동으로 클라이언트 컴포넌트
다른 서버 컴포넌트에서도 사용할 가능성이 있는 컴포넌트 ✅ 필요함 서버에서도 사용할 가능성이 있기 때문에 명확하게 'use client' 선언
버튼, 모달 같은 UI 컴포넌트 ✅ 필요함 독립적으로 사용될 가능성이 높음

3. 서버 컴포넌트와 클라이언트 컴포넌트 간 props 전달 제한이 있을까?

서버 컴포넌트에서 클라이언트 컴포넌트로 직접 전달할 수 없는 prop 유형

  1. 함수 (Function)
    • 예: 이벤트 핸들러 (onClick 등)
  2. 클래스 인스턴스 (Class Instances)
    • 예: Date, Map, Set 등의 인스턴스
  3. React 요소 (JSX, Component)
    • 예: <Component /> 같은 리액트 엘리먼트
  4. Symbol 및 BigInt
    • 직렬화 불가능한 값들

정리하면 직렬화 불가능한 값(JSON으로 표기할 수 없는 값)들은 서버 컴포넌트에서 클라이언트 컴포넌트로 넘길 수 없다. 실제로 하위 컴포넌트가 ‘use client’를 선언한 클라이언트 컴포넌트 일 떄 직렬화 불가능한 값들을 props로 선언해두면 경고가 뜬다. 이는 ‘서버 컴포넌트에서 호출될 가능성’이 있다고 알려주는 경고이다. 호출되지 않을 수도 있기에 경고로 나타나고 에러로 나타나지 않는 것 같다.

마치며

SSR과 CSR을 함께 사용하여 두 렌더링의 장점을 모두 이용한 페이지를 만들어 나가길 바란다. SSR과 CSR의 개념과 장단점에 대해는 이전 포스팅(CSR과 SSR)에 남겨두었으니 참고하면 좋을 것 같다.

참고 자료

https://nextjs.org/docs/app/api-reference/directives/use-client#reference

 

Directives: use client | Next.js

Learn how to use the use client directive to render a component on the client.

nextjs.org

https://react.dev/reference/rsc/use-client

 

'use client' directive – React

The library for web and native user interfaces

react.dev

 

반응형