해결된 질문
작성
·
40
0
클라이언트 컴포넌트안의 자식컴포넌트들은 자동으로 클라이언트 컴포넌트로 바뀌는데 사용할 자식 컴포넌트를 children으로 처리하면 클라이언트 컴포넌트로 바뀌지 않고 서버컴포넌트로 남기때문에 문제가 발생하지 않는건가요? 그렇다면 그게 가능한 메커니즘은 무엇인지 궁금합니다 ㅠㅠ
답변 1
1
안녕하세요! 질문 주신 내용에 답변을 하기 위해서 먼저 next.js 에서 렌더링이 어떤 과정을 통해 이루어지는지를 먼저 설명드려야할 거 같습니다.
nextjs 에선 서버에서 2단계 클라이언트에서 3단계에 걸쳐 렌더링이 일어나게 되는데요. 그 과정은 아래와 같습니다.
서버
리액트는 서버 컴포넌트를 react server component payload(RSC Payload) 의 형태로 먼저 렌더링하게 됩니다.
RSC Payload 는 압축된 바이너리 표현으로 아래와 같은 정보를 포함하고 있습니다.
서버 컴포넌트 렌더링 결과물
클라이언트 컴포넌트가 렌더링될 위치와 해당 자바스크립트 파일에 대한 참조를 위한 placeholder
서버 컴포넌트에서 클라이언트 컴포넌트로 전달된 모든 소품
그리고 이 rsc payload 와 javascript instructions 을 사용해 서버에서 초기 html 생성해 클라이언트에 보냅니다.
클라이언트
클라이언트는 초기 html 를 즉시 표시하고 이 초기 html 은 non-interactive 하고 초기 로드에만 사용됩니다.
클라이언트에서 rsc payload 를 사용해 클라이언트 컴포넌트를 채워넣고(reconcile) dom을 업데이트 합니다.
서버에서 받은 javascript instructions 을 사용해 클라이언트 컴포넌트에 hydrate 합니다.
위와 같은 렌더링 과정을 거치는데요. 과정을 보면 클라이언트 컴포넌트는 서버에서 "클라이언트 컴포넌트가 렌더링될 위치와 해당 자바스크립트 파일에 대한 참조를 위한 placeholder" 의 정보만 가지고 있기 때문에 클라이언트 컴포넌트 내부가 어떻게 구현되어 있는지, 어떻게 렌더링이 되는 지 서버에서는 알지 못합니다. 따라서 그 하위에 있는 컴포넌트 역시도 자연스럽게 클라이언트 컴포넌트로 처리하게됩니다. 하지만 props로 받은 서버 컴포넌트는 상위(서버컴포넌트)에서 받기 때문에 이미 렌더링된 결과가 props로 들어오게 되고 rsc payload에는 이 props 정보도 있기 때문에 서버 컴포넌트를 유지하면서 받을 수 있게 됩니다. 아래 코드를 보면 좀 더 이해하시기 쉬울 거 같아요.
export default function ClientComponent({
children,
}: {
children: React.ReactNode
}) {
const [count, setCount] = useState(0)
return (
<>
<button onClick={() => setCount(count + 1)}>{count}</button>
{children}
</>
)}
import ClientComponent from './client-component'
import ServerComponent from './server-component'
// Pages in Next.js are Server Components by default
export default function Page() {
return (
<ClientComponent>
// 이렇게 children 으로 들어오는 컴포넌트는 상위 서버 컴포넌트에서 렌더링을 마친 후
// props 로 들어오기 때문에 서버 컴포넌트로 유지할 수 있습니다.
<ServerComponent />
</ClientComponent>
)}
참고:
아!! 이미 상위 서버 컴포넌트에서 렌더링이 되어 들어가기 때문이였군요. 정확히 이해됐습니다 감사합니다~