'use client'는 파일 맨 위에 적어 "여기서부터 클라이언트 번들에 들어간다"는 경계를 선언하는 지시어(Directive)다. 경계 파일과 그 파일이 import하는 모듈은 모두 클라이언트 컴포넌트가 된다. state, Effect, 이벤트 핸들러, 브라우저 API(Application Programming Interface)가 필요한 곳에 쓴다.
- 경계에만 한 번 쓴다. 아래로 import되는 컴포넌트에 일일이 붙일 필요가 없다
- 이름과 달리 클라이언트 컴포넌트도 첫 요청에서는 서버에서 HTML(HyperText Markup Language)로 미리 렌더되고, 브라우저에서 하이드레이션된다
- 클라이언트 컴포넌트는 서버 컴포넌트를 import할 수 없다. 클라이언트에서 다시 렌더될 때 서버 코드를 실행할 수 없기 때문이다. 하지만
children이나 prop으로 서버 컴포넌트를 받는 것은 된다. 서버에서 이미 렌더된 결과가 들어가기 때문이다
// ThemeProvider는 'use client'지만, 안쪽 Page는 서버 컴포넌트로 남는다
<ThemeProvider>
<Page />
</ThemeProvider>그래서 테마·인증 같은 Provider를 최상단에 둬도 앱 전체가 클라이언트로 바뀌지 않는다. 부모·자식 관계가 아니라 누가 import했는가가 기준이다
- 경계를 작게 유지한다. 페이지 전체가 아니라 좋아요 버튼처럼 상호작용하는 잎사귀만 클라이언트로 두면 보내는 JS(JavaScript)가 준다(코드 스플리팅과 동적 임포트, 번들 크기 줄이기)
- 서버에서 클라이언트로 넘기는 props는 직렬화할 수 있는 값이어야 한다. 일반 함수는 안 되고(서버 함수는 예외), Promise는 된다(use()로 Promise 읽기, RSC 페이로드(Flight))
useSearchParams같은 훅이 미리 렌더를 깨는 경우는 CSR bailout
서버 쪽은 React 서버 컴포넌트(RSC), 서버 함수를 클라이언트에서 부르는 지시어는 'use server'(서버 함수와 서버 액션).