RSC 이해하기


### 참고문헌
- React : [# React Server Components](https://react.dev/reference/rsc/server-components)
- Nextjs : [# Server Components](https://nextjs.org/docs/app/building-your-application/rendering/server-components)

## React Server Component(React 문서)
- React Server Component(이하 RSC)는 클라이언트와 SSR이 분리된 환경에서 빌드 직전 미리 렌더되는 컴포넌트이다.
- Server component는 빌드 직전 코딩된 템플릿을 이용하여 client side 코드를 자동 생성해내는 기능이라 봐야 할 듯 하다. SSR과는 완전 다른 개념이다. 
- React 19버전부터 정식 지원되지만 Nextjs를 사용하면 RSC를 이용할 수 있다. 

### Server가 없는 경우
- 일반 텍스트파일을 불러와 컴포넌트에 채워넣는 형식이 있을 것이다. 이런 경우는 서버가 없다고 봐야할 것이다.
- server component는 이러한 경우 빌드시 로직을 수행한 후 그 결과를 컴포넌트에 미리 지정된 위치에 변환해둔다.
- marked, sanitize-html 등의 라이브러리를 이용할 수 있다.

### Server가 있는 경우 
- 백엔드 api를 콜하는 로직이 수행될 수 있다. 이러한 경우에도 Server가 없는 경우와 동일하게 동작한다. 
- 빌드시 api 콜한 결과가 컴포넌트에 지정된 위치에 변환되어 들어가게 된다.

[!NOTE] SSR과 다를 바가 없는 것 같은데요. 
여기까지만 내용을 본다면 SSR과 별반 다를게 없어 보인다. 다음의 두 가지를 더 살펴보자

[!NOTE] Server Component용 directive는 없습니다.
"use server"는 Server Action을 사용하기 위한 directive이다.  directive가 없으면 Server Component로 동작한다.


### 상호작용성interactivity를 server component에 추가하기
- Notes 는 서버 컴포넌트이면 컴포넌트 내에서 useState를 사용하는 Expandable 컴포넌트를 import하고 있다.

```
// Server Component
import Expandable from './Expandable';

async function Notes() {
  const notes = await db.notes.getAll();
  return (
    <div>
      {notes.map(note => (
        <Expandable key={note.id}>
          <p note={note} />
        </Expandable>
      ))}
    </div>
  )
}
```

- useState는 client 즉, 브라우저에서 동작하므로 sever component에서는 사용할 수 없는 기능이다. 따라서 "use client" directive를 추가하여 server component가 아님을 표시해주어야 한다.(기억하자. default는 server component이다.)

```
// Client Component
"use client"

export default function Expandable({children}) {
  const [expanded, setExpanded] = useState(false);
  return (
    <div>
      <button
        onClick={() => setExpanded(!expanded)}
      >
        Toggle
      </button>
      {expanded && children}
    </div>
  )
}
```

- 빌드 결과

```
<head>
  <!-- the bundle for Client Components -->
  <script src="bundle.js" />
</head>
<body>
  <div>
    <Expandable key={1}>
      <p>this is the first note</p>
    </Expandable>
    <Expandable key={2}>
      <p>this is the second note</p>
    </Expandable>
    <!--...-->
  </div> 
</body>
```

### 비동기 처리하기

- async를 사용하면 `<Suspense>`를 사용하여 데이터가 로딩 중임을 표시할 수 있다. 

```
// Server Component
import db from './database';

async function Page({id}) {
  // Will suspend the Server Component.
  const note = await db.notes.get(id);
  
  // NOTE: not awaited, will start here and await on the client. 
  const commentsPromise = db.comments.get(note.id);
  return (
    <div>
      {note}
      <Suspense fallback={<p>Loading Comments...</p>}>
        <Comments commentsPromise={commentsPromise} />
      </Suspense>
    </div>
  );
}
```

- await 는 "use client"를 지원하지 않으므로 `use()`를 사용하였다.

```
// Client Component
"use client";
import {use} from 'react';

function Comments({commentsPromise}) {
  // NOTE: this will resume the promise from the server.
  // It will suspend until the data is available.
  const comments = use(commentsPromise);
  return comments.map(commment => <p>{comment}</p>);
}
```

## RSC (Nextjs 문서)
- RSC를 사용하면 서버에서 렌더링하고 선택적으로 캐시할 수 있는 UI를 작성할 수 있다. 
- App Router를 사용하면 Server Component와 같은 최신의 기능을 사용할 수 있다. 스트리밍 및 부분 렌더링을 활성화하기 위해 경로 세그먼트별로 추가 분할되며 3가지 서버 렌더링 전략이 있다.
	- Static Rendering
	- Dynamic Rendering
	- Streaming
    
### Server Rendering의 이점
- Data Fetching
- Security
- Caching
- Performance
- Initial Page Load and First Contentful Paint
- Search Engine Optimization and Social Network Shareablility
- Streaming

### Next.js에서 Server Component 사용하기
- 기본적으로 server component로 동작하므로 별다른 설정이 필요없지만 클라이언트 컴포넌트를 사용하려면 'use client' directive가 필요하다.

### Next.js에서 Sever Component가 렌더되는 방법
- React의 RSC api를 이용하여 렌더링을 조정한다.(React 문서 참고)
- 렌더링은 경로 세그먼트와 Suspense 경계를 기준으로 분할되어 동작한다. 
- chunk파일은 
	- RSC payload 형태로 렌더링 하고 payload와 client component를 html로 최종 렌더링한다.
- 클라이언트에서
	- 초기 로드시 html을 즉시 보여준다.
	- payload는 클라이언트 및 서버 구성 요소 트리를 조정하고 DOM을 업데이트하는 데 사용된다.
	- JavaScript 지침은 클라이언트 구성 요소를 하이드레이션하고 애플리케이션을 대화형으로 만드는 데 사용된다.

### Static Rendering 전략 (default)
- 정적 렌더링을 사용하면 경로가 빌드 시 렌더링되거나 데이터 재검증 후 백그라운드에서 렌더링된다
- 정적 렌더링은 경로에 사용자에게 개인화되지 않은 데이터가 있고 정적 블로그 게시물이나 제품 페이지와 같이 빌드 시 알 수 있는 데이터가 있는 경우 유용하다

### Dynamic Rendering 전략
- 동적 렌더링을 사용하면 request마다 각 사용자에 대한 경로가 렌더링됩니다
- 동적 렌더링은 경로에 사용자에게 맞춤화된 데이터가 있거나 쿠키나 URL의 검색 매개변수와 같이 요청 시에만 알 수 있는 정보가 있는 경우 유용하다
- Nextjs는 동적렌터링을 알아서 처리해주지만 특정 데이터를 캐시하거나 재검증할 시기를 선택하고 UI의 일부를 스트리밍하도록 선택할 수도 있습니다.
- 동적 기능은 사용자 쿠키, 현재 요청 헤더 또는 URL의 검색 매개변수와 같이 요청 시에만 알 수 있는 정보에 의존한다
	- cookies()
	- headers()
	- searchParams

### Streaming 전략
- 스트리밍을 사용하면 서버에서 UI를 점진적으로 렌더링할 수 있다. 작업은 여러 단위로 분할되어 클라이언트로 스트리밍되므로 사용자는 전체 콘텐츠의 렌더링이 완료되기 전에 페이지의 일부를 즉시 볼 수 있다.
- App router는 기본적으로 streaming 전략을 사용한다.
- React Suspense, loading.js을 사용하여 경로 세그먼트 스트리밍을 시작할 수 있다. 

댓글

이 블로그의 인기 게시물

Session 대신 JWT를 사용하는 이유

VSCode에서의 VIM 단축키와 키보드 구매 가이드

우분투에서 테스트링크(testlink)와 맨티스(mantis)로 테스팅 서버 구성하기