Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[오혜성] 11장: Next.js 13과 리액트 18 #81

Merged
merged 2 commits into from
Feb 22, 2024
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
175 changes: 175 additions & 0 deletions 11장/오혜성.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,175 @@
# Next.js 13과 리액트 18

## Next.js 13 App dir

* _document에서 하던 CSS-in-JS 초기화 로직을 루트 레이아웃에서 적용
+ `useServerInsertedHtml`
- https://nextjs.org/docs/app/building-your-application/styling/css-in-js
- 과거 useFlushEffects라는 이름의 훅이였음
- useInsertionEffect를 기반으로 함

* page.js
+ props
- params: [...id]와 같은 동적 라우트 파라미터 값
- searchParams

* error.js
+ 레이아웃에서 에러가 발생할 경우 동일 위계의 error 컴포넌트로 이동하지 않음
- <layout><error>{children}</error></layout> 같은 구조이기 때문
- 루트 레이아웃에서 발생한 에러 처리를 위해선 `app/global-error.js` 페이지를 이용

## 리액트 서버 컴포넌트

### 기존 리액트 컴포넌트와 서버 사이드 렌더링의 한계

* 기존의 흐름
+ 리액트 실행에 필요한 코드를 다운로드하고 > 리액트 컴포넌트 트리를 만들고 > DOM에 렌더링
+ 서버에서 DOM을 만들어 오고 > 클라이언트에서 만들어진 DOM을 기준으로 하이드레이션 > 브라우저에서 상태를 추적하고 이벤트 핸들러를 DOM에 추가

* 한계점
+ 자바스크립트 번들 크기가 0인 컴포넌트를 만들 수 없음
- 만약 서버에서만 렌더링하고 클라이언트에서는 결과만 받는다면?
+ 백엔드 리소스에 대한 직접적인 접근이 불가능
+ 자동 코드 분할이 불가능
- React.lazy를 이용해 수동 분할할 수 있지만, 개발자가 기억해야 함
+ 코드 추상화에 드는 비용이 증가함
- 결과인 JSX는 단순하지만 내부 동작이 많을 때, 서버에 위임해 클라이언트의 속도를 높힐 수 있음

결국 서버 사이드 렌더링, 클라이언트 사이드 렌더링 모두 이 문제들을 해결하기에는 조금씩 아쉬움
* 서버 사이드 렌더링의 정적 콘텐츠를 빠르게 제공하고, 서버에 있는 데이터를 손쉽게 제공하는 장점
* 클라이언트 사이드 렌더링은 사용자 인터랙션에 따라 다양한 것들을 제공할 수 있는 장점

이 두 구조의 장점을 모두 취하고자 하는 것이 리액트 서버 컴포넌트

### 서버 컴포넌트

* 서버 컴포넌트
+ 요청이 오면 그 순간 서버에서 딱 한 번 실행될 뿐이므로 상태를 가질 수 없음
+ 렌더링 생명주기 사용 안됨
+ 사용자 정의 훅 X
+ DOM API X
+ 데이터베이스, 내부 서비스, 파일 시스템에 접근 가능
+ 다른 서버 컴포넌트, JSX 혹은 클라이언트 컴포넌트를 렌더링 할 수 있음

* 클라이언트 컴포넌트
+ 브라우저 환경에서만 실행되어 서버 컴포넌트를 불러오거나, 서버 전용 훅이나 유틸리티를 불러올 수 없음
+ 클라이언트 컴포넌트가 자식으로 서버 컴포넌트를 갖는 구조는 가능함
- 서버 컴포넌트는 이미 서버에서 만들어진 트리를 가지고 있을 것이고, 클라이언트 컴포넌트는 그 트리를 삽입해서 보여주기만 하기 때문
+ 나머지는 일반 컴포넌트와 동일함

* 공용 컴포넌트
+ 서버와 클라이언트 모두에서 사용할 수 있음
+ 두 컴포넌트의 모든 제약을 받음

* 서버 컴포넌트를 사용하기 위해서는 번들러나 특정 프레임워크의 도움을 받는 것이 필수적
+ 리액트 팀의 공식 예제에서는 서버 번들링을 위해 `react-server-dom-webpack`을 만들어 활용함
+ 서버 컴포넌트 제안 문서에서는 노골적으로 Next.js 팀과 협업하고 있음을 언급


### 서버 사이드 렌더링과 서버 컴포넌트의 차이

* 서버 사이드 렌더링의 목적은 초기에 인터렉션은 불가능하지만 정적인 HTML을 빠르게 내려주는 데 초점을 두고 있음
+ 따라서 여전히 초기 HTML이 로딩된 이후에는 클라이언트에서 자바스크립트 코드를 다운로드, 파싱, 실행하는 데 비용이 듬

* 이후에는 서버 사이드 렌더링과 서버 컴포넌트를 모두 채택하는 것도 가능해질 것

* 결론적으로 둘은 대체제가 아닌 상호보완하는 개념
+ 리액트 팀에서도 미래에는 두 가지 기법이 모두 쓰일 수 있는 가능성을 암시하고 있음
Comment on lines +74 to +77
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

next 공식문서를 확인하지 않았지만 최초 로딩시에 dom을 내려주는것으로 보아 지금도 어느정도 같이 사용하는게 아닌가 예측중입니다!


### 서버 컴포넌트는 어떻게 작동하는가?

1. 서버가 렌더링 요청을 받음
2. 서버는 받은 요청에 따라 컴포넌트를 JSON으로 직렬화 함.
1. 서버에서 렌더링할 수 있는 것은 직렬화해서 내보내고
2. 클라이언트 컴포넌트로 표시된 부분은 플레이스홀더 형식으로 비워둠
3. 브라우저는 이 결과물을 받아 역직렬화한 다음에 렌더링을 수행함
4. 이처럼 서버에서는 클라이언트에서 리액트 컴포넌트 트리 구성에 필요한 정보를 최대한 많이, 그리고 경제적인 포맷으로 클라이언트에 전달함
3. 브라우저가 리액트 컴포넌트 트리를 구성함

이 작동 방식의 특별한 점

* 서버에서 보낼 때 스트리밍 형태로 보냄으로써 줄 단위로 JSON을 읽고 컴포넌트를 렌더링할 수 있어 되도록 빨리 결과물을 보여줄 수 있음
* 각 컴포넌트별로 번들링이 별개로 돼 있어, 필요에 따라 컴포넌트를 지연해서 받거나 따로 받을 수 있음
* 서버 사이드 렌더링과 달리 결과물이 HTML이 아닌 JSON 형태로 보내짐
+ 리액트 컴포넌트 구조를 받아 리액트 트리의 구성을 최대한 빠르게 할 수 있도록 도와줌

```
이러한 특징으로 서버 컴포넌트로 클라이언트 컴포넌트로 props를 넘길 때 반드시 직렬화 가능한 데이터를 넘겨야 하는 제약이 생김
```

### Next.js에서의 리액트 서버 컴포넌트

* getServerSideProps, getStaticProps, getInitialProps 삭제
+ fetch로 대체

* 리액트 팀에서는 fetch API를 확장해
+ 서버 컴포넌트 트리 내에서 동일한 요청이 있다면 재요청하지 않고 캐싱된 결과를 사용하도록 함

> 🤘 책에서 2023년 5월 기준으로는 타입스크립트가 비동기 컴포넌트를 지원하지 않았다고 하는데
> 타입스크립트 5.1.3. @types/react 18.2.8 에서는 지원한다 합니다
> https://nextjs.org/docs/app/building-your-application/configuring/typescript#async-server-component-typescript-error
Comment on lines +108 to +110
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

여러분들 타입스크립트 버전 어떤 거 쓰고 계셔요? 저희는 4.7.3?,,

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

저희도 4... 4.8.4

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

5.1.6...


### 정적 렌더링과 동적 렌더링

* 기본적으로 빌드 타임에 렌더링을 미리 해둠
+ 이를 요청마다 fetch하고 싶다면 `cache: 'no-cache` 옵션으로 fetch를 사용하면 됨
+ 혹은 next/headers나 next/cookie 같은 함수를 사용하면, 동적인 연산을 바탕으로 결과를 반환하는 것으로 인식해 정적 렌더링 대상에서 제외됨

* 동적인 주소이지만 특정 주소에 대해 캐싱하고 싶은, getStaticPaths를 흉내내고 싶다면?
+ `generateStaticParams`를 사용하면 됨
+ https://nextjs.org/docs/app/api-reference/functions/generate-static-params

```
fetch(URL, { cache: 'force-cache' })
- getStaticProps, 불러온 데이터로만 관리

fetch(URL, { cache: 'force-cache' }),
fetch(URL, { next: {revalidate: 0} })
- getServerSideProps, 캐싱하지 않고 매번 새로운 데이터를 불러옴

fetch(URL, { next: {revalidate: 10} })
- ISR, 정해진 시간 동안에 캐싱된 값을 반환하고 이후 캐시를 파기
```

### 스트리믕을 활용한 점진적인 페이지 불러오기

* app/loading.js는 Suspense 기반

### 서버 액션

```tsx
async function serverAction() {
"use server";
}

// or

"use server";

async function serverAction() {}
```

* 이벤트를 발생시키는 것은 클라이언트지만, 실제로 함수 자체가 수행되는 것은 서버
+ 서버 액션을 클라이언트에서 실행시 네트워크 탭에서는 현재 라우트 주소와 ACTIONS_ID만 보냄
+ 이를 이용해 서버에서 직접 실행함
+ 클라이언트 번들링 결과물에 포함되지 않음

* server mutation
+ 'next/nagivation'의 redirect
+ 'next/cache'의 revalidatePath와 revalidateTag

* 주의점
+ 서버 액션은 클라이언트 컴포넌트 내에서 정의할 수 없음
- 하지만 서버 액션만 모여 있는 파일에서 import하거나, props로 받아 useTransition과 함께 사용할 수 있음

> 🤘 실사용 코드보면서 저는 심적 표상을 잡는 편인데 ...
> https://github.com/gabrielelpidio/next-infinite-scroll-server-actions
> 이게 기억이 나 남겨봅니다..
Comment on lines +165 to +167
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

오오옹


## 정리

리액트의 서버 컴포넌트는 이전에 없었던 완전히 새로운 패러다임으로, 앞으로의 리액트 생태계에 많은 변화를 가져올 것으로 보임

그에 따라 프런트엔드 개발자들에게 Node.js를 위시하는 서버 환경의 이해가 중요해질 것

다가오는 변화에 앞서 먼저 체험해 보고, 개발 중인 애플리케이션의 문제점을 어떻게 해결하고 성능을 개선할 수 있을지 고민해 보면 좋을 것이다
Loading