React 서버 컴포넌트를 사용하면 서버에서 렌더링하고 선택적으로 캐시할 수 있는 UI 를 작성할 수 있다. Next.js 에서는 경로 Segement 별로 렌더링 작업을 추가로 분할해서 Streaming 과 부분 렌더링이 가능하게 한다. 서버 렌더링에는 세 가지 전략이 있다.
- 정적 렌더링
- 동적 렌더링
- Streaming
이 페이지에서는 서버 컴포넌트가 어떻게 작동하는지, 언제 사용하는지와 다양한 서버 렌더링 전략에 대해 설명한다.
1. 서버 렌더링의 이점
서버 렌더링에서 렌더링 작업을 하면 여러 이점이 있다. (* 이점은 중요하니 공식문서와 다르게 소주제로 다룬다)
1-1) 데이터 가져오기
서버 컴포넌트를 사용하면 데이터 소스에 더 가까운 서버로 데이터를 가져올 수 있다. 렌더링에 필요한 데이터를 가져오는 데 걸리는 시간을 줄이고, 클라이언트가 요청해야 할 요청 수를 줄여서 성능을 향상시킬 수 있다.
1-2) 보안
서버 컴포넌트를 사용하면 토큰이나 API 키와 같은 민감한 데이터와 로직을 클라이언트에 노출시키지 않을 수 있다.
1-3) 캐싱
서버에서 렌더링하면 결과를 캐시하고 이후 요청과 다른 사용자 간에 재사용할 수 있다. 이는 각 요청에 대한 렌더링과 데이터 가져오는 시간을 줄여서 성능을 향상시키고 비용을 절감할 수 있다.
1-4) 성능
서버 컴포넌트는 기본 성능을 최적화하는 도구들을 추가적으로 제공한다. 예를 들어, 전적으로 클라이언트 컴포넌트로 구성된 앱에서 시작하는 경우, 상호 작용 하지 않는 UI 의 일부를 서버 컴포넌트로 이동하면 클라이언트 사이드의 JS 양을 줄일 수 ㅇㅆ다. 이는 인터넷 속도가 느리거나 성능이 떨어지는 기기를 사용하는 사용자에게 유리하다.
1-5) 데이터 가져오기
서버 컴포넌트를 사용하면 데이터 소스에 더 가까운 서버로 데이터를 가져올 수 있다. 렌더링에 필요한 데이터를 가져오는 데 걸리는 시간을 줄이고, 클라이언트가 요청해야 할 요청 수를 줄여서 성능을 향상시킬 수 있다.
1-6) FCP(초기 페이지 로드와 첫 번재 콘텐츠 도달 시간)
서버에서는 사용자가 클라이언트에서 JS 를 다운로드, 파싱, 실행하는 시간을 기다리지 않고 페이지를 즉시 볼 수 있도록 HTML 을 생성할 수 있다.
1-7) 검색 엔진 최적화, 소셜 네트워크 공유
렌더링된 HTML 은 검색 엔진 봇이 페이지를 인덱싱하고 소셜 네트워크 봇이 페이지에 대한 소셜 카드 미리보기를 생성하는데 사용할 수 있다.
1-8) Streaming
서버 컴포넌트는 렌더링 작업을 여러 조각으로 분할하고 준비되는 대로 클라이언트에 스트리밍할 수 있다. 이를 통해서 사용자는 전체 페이지가 서버에서 렌더링될 때까지 기다릴 필요 없이 페이지의 일부를 더 일찍 볼 수 있다.
2. Next.js 에서 서버 컴포넌트 사용하기
기본적으로 Next.js 는 서버 컴포넌트를 사용한다. 추가 구성 없이 자동으로 서버 렌더링을 구현할 수 있으며, 필요할 때 클라이언트 컴포넌트를 사용하도록 한다.
3. 서버 컴포넌트는 어떻게 렌더링되는가?
서버에서 Next.js 는 React API 를 활용해서 렌더링한다. 렌더링 작업은 개별 경로 Segement 와 Suspense Boundary 경계로 청크가 나뉜다. 각각의 청크는 두 가지 단계를 거쳐서 렌더링된다.
- React 는 서버 컴포넌트를 **React Server Component Payload(RSC Payload)** 라는 특수 데이터 형식으로 렌더링한다.
- Next.js 는 RSC Payload 와 클라이언트 컴포넌트 JS 지시 사항(JS instruction)을 사용해 서버에서 HTML 파일을 렌더링한다.
그 다음, 클라이언트에서는 아래의 단계를 거친다.
- HTML 은 해당 경로에서 아무런 상호작용할 수 없지만 빠르게 보여줄 수 있는 화면을 만드는데 사용된다. 그리고 이것은 처음 페이지를 로딩할 때만 그렇다.
- RSC Payload 는 클라이언트 컴포넌트, 서버 컴포넌트를 조정하고 DOM 을 업데이트한다.
- JS 지시사항은 클라이언트 컴포넌트들을 **hydrate** 해서 애플리케이션을 상호작용되도록 한다.
3-1) RSC Payload
RSC Payload 는 렌더링된 React 서버 컴포넌트 트리를 컴팩트한 이진트리로 표현한 것이다. 클라이언트에서 React 가 브라우저 DOM 을 업데이트 하는데 사용된다. RSC Payload 는 다음이 포함된다.
- 서버 컴포넌트의 렌더링 결과
- 클라이언트 컴포넌트가 렌더링될 위치의 placeholder 와 그 JS 파일에 대한 참조
- 서버 컴포넌트에서 클라이언트 컴포넌트로 전달한 모든 props
4. 서버 렌더링 전략
서버 렌더링 전략으로 다음의 세 가지가 있다. Static(정적), Dynamic(동적), Streaming
4-1) Static (기본 설정)
정적 렌더링에서는 빌드 타임에 해당 경로를 렌더링하거나 데이터를 검증(한 후에 백그라운드에서 렌더링한다. 결과는 케시되어 CDN 으로 전송할 수 있다. 이 최적화는 사용자들과 서버 요청 간에 렌더링 결과를 공유할 수 있게 한다.
정적 렌더링은 사용자마다 달라지는 데이터가 없고, 빌드 타임에 명확히 알 수 있는 데이터를 활용하는 경로에서 유용하게 사용될 수 있다. 예를 들면, 블로그 포스트다 상품 페이지 같은 것들.
4-2) Dynamic
동적 렌더링에서는 각 사용자의 요청에 경로를 렌더링한다. 동적 렌더링은 사용자별로 달라지는 데이터가 있는 경로 요청이나 요청한 시점에만 알 수 있는 정보(쿠키, URL 의 params)들이 포함된 경로에서 유용하게 사용할 수 있다.
(1) 캐싱된 데이터를 활용한 동적 렌더링
대부분의 웹 사이트에서는 경로가 완전히 정적이거나 완전히 정적이지 않다. 예를 들어, 이커머스 페이지 중에는 매시간마다 업데이트 하는 캐싱된 상품 데이터를 사용하면서 캐시되지 않은 개인화된 데이터를 가진 것도 있을 수 있다. Next.js 에서는 캐싱하거나 캐싱하지 않은 데이터 둘 다 갖는 경로를 동적으로 렌더링할 수 있다. 이것이 가능한 이유는 RSC Payload 와 캐싱이 별도로 이뤄지는 것 덕분이다. 이런 방식으로 인해 요청 시 모든 데이터를 가져오는 성능 영향에 대한 걱정 없이 동적으로 렌더링할 수 있다.
(2) 동적 함수
(* 지금 쓰는 것처럼 공식문서와 달리 동적함수 -> 동적 렌더링으로의 전환 이 순서로 읽는 것이 더 이해가 쉬워서 순서를 변경해봤다) 동적 함수는 요청하는 시점에서만 알 수 있는 정보, 예를 들어 사용자의 쿠키, 현재 요청의 헤더, URL 의 params 에 의존한다.
- **cookies()**, **headers()**
: 이 함수들은 서버 컴포넌트에서 사용함녀 전체 경로가 요청 시에 동적 렌더링으로 설정된다. - **searchParams()**
: 페이지에서 searchParams Prop 을 사용하면 해당 페이지는 요청 시에 동적 렌더링으로 설정된다.
위 함수들 중 어느 하나를 사용하면 전체 경로가 요청 시에 동적으로 렌더링하는 방식을 선택하게 된다.
(3) 동적 렌더링으로 전환
렌더링 중에 동적 함수나 캐시되지 않은 데이터 요청이 발견되면, Next.js 는 전체 경로를 동적으로 렌더링하도록 전환한다. 아래의 표는 동적 함수와 데이터 캐싱이 렌더링 방식에 어떻게 영향을 주는지를 보여주는 표다.
동적 함수 | 데이터 | 렌더링 방식 |
없음 | 캐싱됨 | 정적 렌더링 |
있음 | 캐싱됨 | 동적 렌더링 |
없음 | 캐싱되지 않음 | 동적 렌더링 |
있음 | 캐싱되지 않음 | 동적으로 렌더링 |
위 표에서 알 수 있듯이, 모든 데이터가 캐시돼야만 정적 렌더링을 한다. 그러나 캐시된 데이터와 캐시되지 않은 데이터 가져오기를 모두 사용하는 경우에는 동적 렌더링을 한다.
개발자로서 정적 렌더링할 것인지, 동적 렌더링할 것인지 선택하지 않아도 되는게, Next.js 가 사용된 기능과 API 에 따라서 각 경로별 최적의 렌더링 전략을 자동으로 선택한다. 대신에 특정 데이터를 캐시하거나 재검증 할 때를 선택하고, UI 의 일부를 Streaming 하도록 설정할 있다.
4-3) Streaming
Streaming 을 활용해 서버에서 UI 를 점진적으로 렌더링할 수 있다. 작업은 여러 청크로 분할하고 준비되는 대로 클라이언트에 streaming 된다. 사용자는 전체 컨텐츠가 렌더링을 완료하기 전에 페이지의 일부를 즉시 볼 수 있게 된다.
Streaming 은 기본적으로 Next.js 의 **App Router** 에 내장돼 있다. 이는 초기 페이지 로딩 성능과 로딩 속도가 느린 데이터를 가져오는 UI 성능을 개선하는데 도움을 준다. 예를 들면 제품 페이지 리뷰 등이 있다.
loading.js 와 같이 React **Suspense** 를 활용해 경로 Segement 스트리밍을 시작할 수도 있다.
Reference
https://nextjs.org/docs/app/building-your-application/rendering/server-components
Rendering: Server Components | Next.js
Learn how you can use React Server Components to render parts of your application on the server.
nextjs.org
'(준)공식 문서 > Next.js' 카테고리의 다른 글
[ Next.js 공식 문서 ] Rendering (2) - Composition Pattern (1) | 2024.04.15 |
---|---|
[ Next.js 공식 문서 ] Rendering (2) - Client Component (0) | 2024.04.14 |
[ Next.js 공식 문서 ] Rendering (0) - Rendering (0) | 2024.04.14 |
[ Next.js 공식 문서 ] Routing (12) - Middleware (0) | 2024.04.10 |
[ Next.js 공식 문서 ] Routing (11) - Intercept Routes (0) | 2024.04.09 |