Server and Client Composition Patterns
React application 을 설계할 때 어떤 부분은 서버에서 어떤 부분은 클라이언트에서 렌더링될지 고민할 필요가 있습니다.
When to use Server and Client Components ?
Server Component Partterns
Sharing data between components
서버에서 데이터를 패칭할 때 다른 컴포넌트들에게 데이터를 공유할 필요가 있습니다.
예를 들어보자면 레이아웃과 페이지가 동일한 데이터에 의존하고 있을 수가 있습니다.
서버에서 사용할 수 없는 React Context 나 Props 를 넘기는 것 대신에 fetch 또는 React 의 cache 를 통해
같은 데이터를 위해 중복적인 데이터 요청에 대한 걱정 없이 데이터를 필요로하는 컴포넌트들에 동일한 데이터를 패칭할 수 있습니다.
리액트는 fetch 를 확장해 데이터 요청을 자동으로 메모할 수 있으며 fetch 를 사용할 수 없을 경우 캐시 기능을 사용할 수 있습니다.
Keeping Server-only Code out of the Client Environment
자바스크립트 모듈은 서버 및 클라이언트에서 공유되어 사용될 수 있으므로
서버에서만 실행되도록 의도했던 코드가 클라이언트에 몰래 들어갈 수 있습니다.
해당 함수는 서버에서만 실행되도록 의도하여 작성된 API_KEY 가 포함되어 있습니다.
해당 환경 변수는 NEXT_PUBLIC 가 붙지 않으므로 서버에서만 액세스 할 수 있는 비공개 변수입니다.
환경변수가 클라이언트로 유출되는 것을 방지하기 위해 Next.js 는 비공개 환경 변수를 빈 문자열로 대체합니다.
의도하지 않은 클라이언트의 서버 코드 사용을 방지하기 위해 server-only 와 같은서버 전용 패키지를 사용해
다른 개발자가 실수로 이러한 모듈을 클라이언트 컴포넌트로 가져온 경우 빌드타임 오류를 발생시킬 수 있습니다.
Using Third-party Packages and Providers
대부분의 Third-party Pacakges 는 클라이언트 컴포넌트의 기능을 사용하고 있지만
"use client"와 같은 지시자가 없는 케이스가 많습니다.
이러한 경우 서버 컴포넌트에서는 해당 Third-party Packages 를 바로 가져와 사용할 수 없습니다.
이럴 경우 서버 컴포넌트에서 사용할 수 있도록 랩핑해서 사용할 수 있습니다.
이렇게 "use client" directive 를 넣어주면 서버 컴포넌트에서도 import 해서 사용할 수 있습니다.
Client Components
Moving Client Components Down the Tree
번들 사이즈를 줄이기 위해 next 에서는 Client Component 를 컴포넌트 트리의 아래에 위치하기를 권장한다고 합니다.
예를 들어 레이아웃 컴포넌트가 정적인 엘리먼트와 상태를 사용하는 인터렉티브한 요소가 있다고 했을 때
정적인 엘리먼트 요소들은 서버 컴포넌트에 유지하고 인터렉티브한 요소는 클라이언트 컴포넌트로 이동시키는 방법을 통해
모든 레이아웃의 컴포넌트를 클라이언트로 보내는 것을 방지할 수 있다고 합니다.
서버 컴포넌트에서 데이터를 가져올 경우 이를 클라이언트 컴포넌트에 props 로 전달할 수 있습니다.
서버에서 클라이언트 컴포넌트로 전달되는 props 는 React 에 의해 직렬화가 가능해야 합니다.
(서버 -> 클라이언트 컴포넌트의 순서로 되어야 한다는 말인 것 같음 ?.. 아닌 것 같음)
클라이언트 컴포넌트가 직렬화할 수 없는 데이터에 의존하는 경우 클라이언트에서 타사 라이브러리를 사용해 데이터를 가져오거나
서버에서 Route Handler 를 사용해 데이터를 가져올 수 있습니다.
Interleaving Server and Client Components
서버와 클라이언트 컴포넌트를 섞어 사용하는 경우 UI 를 컴포넌트 트리로 시각화하면 도움이 될 수 있습니다.
루트 레이아웃에서 시작해 "use client" 지시자를 추가해 특정 컴포넌트 하위 트리를 클라이언트에서 렌더링 할 수 있습니다.
클라이언트 하위 트리 내에서도 서버 컴포넌트를 중첩하거나 Server Action 을 호출할 수 있습니다.
하지만 몇 가지 주의해야 할 점이 있습니다.
1. 응답-요청 라이프 사이클 동안 코드는 서버에서 클라이언트로 이동합니다.
클라이언트에서 서버에 있는 리소스나 리소스에 접근할 필요가 있다면 서버와 클라이언트 간에 전환하는 것이 아닌
서버로의 새 요청을 생성하는 것입니다.
2. 서버로 새 요청이 생성되면 클라이언트 컴포넌트 내에 중첩된 서버 컴포넌트도 포함해 모든 서버 컴포넌트가 먼저 렌더링 되고
렌더링 결과(RSC Payload) 는 클라이언트 컴포넌트의 위치 참조를 포함하고 있습니다.
클라이언트에서는 React 가 RSC Payload 를 사용해 서버 및 클라이언트 컴포넌트를 하나의 트리로 통합합니다.
3. 클라이언트 컴포넌트는 서버 컴포넌트 후에 렌더링되므로, 클라이언트 컴포넌트 모듈 내에서 서버 컴포넌트를 가져올 수 없습니다.
이는 서버로 다시 요청을 요구하기 때문입니다. 대신 서버 컴포넌트를 클라이언트 컴포넌트에 props 로 전달할 수 있습니다.
Unsupported Pattern : Importing Server Components into Client Components
Supported Pattern : Passing Server Components to Client Components as Props
서버 컴포넌트를 클라이언트 컴포넌트에 props 로 전달할 수 있습니다.
일반적인 패턴은 React 의 children prop 을 사용해 클라이언트 컴포넌트에 "슬롯"을 만드는 것입니다.
아래 예시에서 <ChildrenComponent> 는 children prop 을 받습니다.
<ClientComponent> 는 children 이 서버 컴포넌트로 채워질 것이라는 것을 알 수 없습니다.
<CilentComponent> 의 유일한 책임은 children 이 어디에 배치될지 결정하는 것입니다.
부모 서버 컴포넌트에서 <ClientCompoent> 와 <ServerComponent> 를 모두 가져와
<ServerComponent> 를 <ClientComponent> 의 자식으로 전달할 수 있습니다.
이 방식에서는 <ClientComponent> 와 <ServerComponent> 가 분리되어 독립적으로 렌더링 될 수 있습니다.
이 경우 자식인 <ServerComponent> 는 클라이언트에서 <ClientComponent> 가 렌더링되기 전에 서버에서 렌더링 할 수 있습니다.
Good to know:
부모 컴포넌트가 다시 렌더링될 때 중첩된 자식 컴포넌트의 재랜더링을 방지하기 위해 lifting content up" 패턴이 사용됐습니다.
children prop 에만 국한되지 않으며 JSX 를 전달하기 위해 어떤 prop 이든 사용할 수 있습니다.
'NEXT 공부 > 2. Rendering' 카테고리의 다른 글
2. Client Components (1) | 2024.10.21 |
---|---|
1. Server Components (0) | 2024.10.21 |