Nextjs에서 client 컴포넌트란 무엇이고 Server component와의 관계가 어떻게 되는 것인이 확인을 위한 문서 정리
기본으로 다 Server Component이다.
렌더링 전략이 3가지가 있다.
cookies(), headers(), searchParams()클라이언트 사이드에서 hydration(수화)가 발생하는 컴포넌트이다.
-> 일반적으로 알고있는 리액트 컴포넌트 개념으로 생각하자. (참고)
서버사이드에서 prerednered 된다
"use client" 디렉티브를 사용해서 클라이언트 컴포넌트라고 명시한다.
해당 컴포넌트 내, 자식 모두 클라이언트 번들에 포함된다.
여러 컴포넌트에 "use client"를 정의할 수 있는데 이는 여러 개의 클라이언트 번들로 쪼갤 수 있게 해준다.
그러나 클라이언트 컴포넌트의 자식까지 모두 "use client"를 명시해줄 필요는 없다. (자식, import된 모듈 등 모드 클라이언트 번들의 일부로 간주된다.)
렌더링 방식은?
풀 페이지 로드를 할 때랑 후속 탐색인지에 따라 달라진다.
리액트는 Server component는 React Server Component Payload (RSC Payload) 형식으로 렌더링 (클라이언트 컴포넌트의 참조가 포함되어 있다.)
→ 클라, 서버 관계 없이 모두 RSC Payload 기반으로 렌더링
Next.js는 RSC Payload Client Component JavaScript 명령을 사용하여 서버에서 HTML을 렌더링
→ JavaScript 명령은 클라 사이드에서 어떤 동작을 해야되는지 명시해둔 것일까? (수화 시에 필요한 js 명령)
이제 클라이언트 사이드에서는
hydration은 이벤트 리스너를 DOM에 붙이는 과정이다. 즉, 상호작용이 가능해진다. hydrateRoot라는 React API를 사용한다.
클라이언트 컴포넌트는 클라이언트 사이드에서 렌더링된다. (without the server-rendered HTML.)
공식문서에서 추천하는 조합 방식에 대해
자바스크립트 모듈은 클라이언트, 서버 컴포넌트 모두에 사용될 수가 있다. (재사용을 위한 api 요청함수를 생각하자)
서버에서만 동작하도록 하기 위해 server-only 패키지를 사용해서 서버 사이드에서만 동작한다는 것을 보장할 수 있다. (클라이언트 컴포넌트에서 import 시 오류가 발생한다.)
import { Carousel } from 'acme-carousel'
export default function Page() {
return (
<div>
<p>View pictures</p>
{/* Error: `useState` can not be used within Server Components */}
<Carousel />
</div>
)
}
'use client'
import { Carousel } from 'acme-carousel'
export default Carousel
import Carousel from './carousel'
export default function Page() {
return (
<div>
<p>View pictures</p>
{/* Works, since Carousel is a Client Component */}
<Carousel />
</div>
)
}
js 번들 사이즈를 줄이기 위해 클라이언트 컴포넌트를 컴포넌트 트리 하단으로 옮기는 것을 권장한다.
→ 클라이언트 컴포넌트를 쪼개서 각각 분리되어 번들에 포함되도록 하는 것
요청-응답 라이프사이클 동안 코드가 서버에서 클라이언트로 이동한다. 클라이언트에서 서버의 데이터나 리소스에 접근해야 하는 경우, 서버로 새로운 요청을 보내야 하며, 서버와 클라이언트 간을 계속해서 전환할 수는 없다.
서버로 새로운 요청이 있을 때, 모든 서버 컴포넌트는 클라이언트 컴포넌트 내에 중첩된 경우도 포함하여 먼저 렌더링. 렌더링된 결과(RSC 페이로드)는 클라이언트 컴포넌트의 위치에 대한 참조를 포함한다. 그런 다음, 클라이언트에서 React는 RSC 페이로드를 사용하여 서버와 클라이언트 컴포넌트를 단일 트리로 결합한다.
클라이언트 컴포넌트에서 서버 컴포넌트를 import하는건 지원하지 않는다.
다만 서버 컴포넌트를 클라이언트 컴포넌트의 props로 넘겨주는 것은 가능하다.
ex) children으로 넘겨주는 방식이 일반적이다.
-> 클라이언트 컴포넌트에 "slot"을 만든다.