likeornament 님의 블로그
[Next.js] Layout에서 클라이언트 컴포넌트로 감쌀 때 렌더링과 성능 이슈 정리 본문
// ToastProvider.tsx
"use client"
import { Toaster } from "react-hot-toast";
export default function ToastProvider() {
return (
<Toaster position="top-center"/>
)
}
react-hot-toast를 사용하기 위해 먼저 Toaster를 감싼 ToastProvider.tsx를 만든다.
// layout.tsx
type Props = {
children: ReactNode;
}
export default function AfterLoginLayout({ children }: Props) {
return (
<>
<ToastProvider>
{children}
</ToastProvider>
</>
)
}
그리고 이렇게 Toaster를 띄울 페이지들의 최상단 layout.tsx에서 children을 ToastProvider로 감싼다.
여기서 생긴 궁금증
layout.tsx는 서버 컴포넌트이고, children으로 들어오는 대부분의 page.tsx 파일들도 서버 컴포넌트인 경우가 많다.
그런데 이 children을 클라이언트 컴포넌트인 ToastProvider로 감쌌을 때 어떤 일이 일어날까?
- ToastProvider는 클라이언트 컴포넌트니까 서버에서는 placeholder만 보내고, children의 HTML은 서버에서 렌더링된 상태로 클라이언트에 보내질까?
- 아니면, children이 클라이언트 컴포넌트로 감싸졌기 때문에, children도 브라우저에서 직접 렌더링해야 할까?
만약 두 번째라면, 성능 저하가 생기는 건 아닐까?
1. 결과 요약
결론부터 말하면:
클라이언트 컴포넌트로 감싸진 children은 서버가 아닌 클라이언트에서 렌더링된다.
따라서 서버 컴포넌트 이점(초기 HTML 스트리밍, 서버 렌더링 최적화 등)은
ToastProvider 아래 있는 children에는 적용되지 않는다.
2. 상세 설명
(1) 서버 컴포넌트를 클라이언트 컴포넌트로 감싸면?
Next.js에서는:
- 서버 컴포넌트는 서버에서 렌더링 되고, 완성된 HTML만 클라이언트로 전송된다.
- 클라이언트 컴포넌트는 브라우저에서 직접 렌더링 및 하이드레이션(hydration)이 필요하다.
그런데 클라이언트 컴포넌트(ToastProvider)가 서버 컴포넌트(children)를 감싸게 된다면?
=> Next.js는 ToastProvider 아래 있는 트리를 모두 클라이언트 컴포넌트처럼 취급한다.
즉, children도 브라우저에서 렌더링과 하이드레이션을 해야 한다.
정리:
클라이언트 컴포넌트가 등장하면 그 하위 트리(children)는 서버가 아닌 클라이언트에서 렌더링된다.
쉽게 말하면 클라이언트 컴포넌트를 만나는 순간 감싸져 있는 그 이후 트리(children)은 서버가 아니라 클라이언트에서 렌더링 된다.
(2) 그렇다면 성능에 문제는?
- ToastProvider 하위 트리(children)가 가벼운 경우: 클라이언트 렌더링 비용이 거의 없어서 큰 문제가 되지 않는다.
- children이 복잡하거나 무거운 경우: 서버가 미리 렌더링해줄 수 있었던 것들을 클라이언트가 직접 렌더링해야 해서,
초기 로딩 속도가 느려질 수 있다.
특히 layout.tsx처럼 여러 page.tsx를 그리는 최상단에서 children을 감싸는 경우, 그 영향이 더 커질 수 있다.
3. 결론
- children이 단순하거나 가볍다면: 클라이언트 컴포넌트로 감싸도 성능 문제는 크지 않다.
- children이 복잡하거나 무거운 경우: 성능 저하(초기 렌더링 지연)가 발생할 수 있다.
따라서 구조를 조금 바꿔서,
<>
{children}
<ToastProvider/>
</>
처럼 children을 ToastProvider로 감싸지 않고, 별도로 ToastProvider를 배치하는 것이 더 안전하다.
'공부 > next.js' 카테고리의 다른 글
[Next.js] Next.js 서버 컴포넌트, 정말 껍데기처럼만 써도 될까? (0) | 2025.04.15 |
---|---|
[Next.js] 서버 컴포넌트에서 prefetchQuery가 실패하는 이유와 useQuery가 만들어낸 착각 (0) | 2025.04.15 |
[Next.js]Next.js 15의 페이지 컴포넌트, 이제는 params와 searchParams만 사용한다 (0) | 2025.04.14 |
[Next.js] params가 갑자기 Promise? Next.js 15가 바꿔놓은 것들 (0) | 2025.04.14 |