---
# System prepended metadata

title: 11장 Next.js 13과 리액트 18
tags: [Book, Frontend, Study]

---

---
title: '11장 Next.js 13과 리액트 18'
created: 2024-05-21 12:00
updated: 2024-05-21 12:00
tags:
  - 'Frontend'
  - 'Study'
  - 'Book'
---

# 중요한 부분 정리

## app 디렉터리의 등장

13버전 이전까지는 모든 페이지는 가각 구별된 파일로 독립되어 있었다.
페이지를 공통으로 무언가를 집어넣을 수 있는 곳은 `_document`, `_app`이 유일하다.
- _document: 페이지에서 쓰이는, 태그를 수정하거나 서버 사이드 렌더링 시 `styled-components`와 같은 일부 CSS-in-JS를 지원하기 위한 코드를 삽입하는 제한적인 용도로 사용.
- _app: 페이지를 초기화하기 위한 용도로 사용되며 다음과 같은 작업이 가능
  - 페이지 변경 시에 유지하고 싶은 레이아웃
  - 페이지 변경 시 상태 유지
  - componentDidCatch를 활용한 에러 핸들링
  - 페이지간 추가적인 데이터 삽입
  - global CSS 주입

이전의 12버전까지는 페이지 공통 레이아웃을 유지할 수 있는 방법은 `_app`이 유일했다. 이러한 레이아웃의 한계를 극복하기 위해 나온 것이 Next.js의 app 레이아웃이다.

### 라우팅

- 기존에 `/pages`로 정의하던 라우팅 방식이 `/app` 디렉터리로 이동
- 파일명으로 라우팅하는 것이 불가능해졌다. 파일명은 무시되고 폴더명까지만 주소로 변환된다.
- 즉, 13의 app 디렉터리 내부의 파일명은 라우팅 명칭에 아무런 영향을 미치지 못한다.


## 리액트 서버 컴포넌트

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

- 자바스크립트 번들 크기가 0인 컴포넌트를 만들 수 없다.
- 백엔드 리소스에 대한 직접적인 접근이 불가능하다.
- 자동 코드 분할이 불가능하다.
- 연쇄적으로 발생하는 클라이언트와 서버의 요청을 대응하기 어렵다.
- 추상화에 드는 비용이 증가한다.

서버 컴포넌트는 위와 같은 한계점을 극복하기 위해 등장했다.

### 서버 컴포넌트란?

하나의 언어, 하나의 프레임워크, 그리고 하나의 API와 개념을 사용하면서 서버와 클라이언트 모두에서 컴포넌트를 렌더링할 수 있는 기법을 의미한다. 서버에서 할 수 있는 일은 서버가 처리하게 두고, 서버가 할 수 없는 나머지 작업은 클라이언트인 브라우저엣에 수행된다.

> 주의해야할 점은 서버컴포넌트는 요청이 오면 그 순간 서버에서 딱 한 번 실행될 뿐ㅇ니므로 상태를 가질 수 없다. 그 말인 즉슨 useState, useReducer와 같은 리액트 생명주기 메서드나 훅을 사용할 수 없다는 뜻이다.

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

1. 서버가 렌더링 요청을 한다.
    - 서버가 렌더링 과정을 수행해야 하므로 리액트 서버 컴포넌트를 사용하는 모든 페이지는 서버에서 시작된다.
    - 루트에 있는 컴포넌트는 항상 서버 컴포넌트다.
3. 서버는 받은 요청에 따라 컴포넌트를 JSON으로 직렬화한다.
    - 서버에서 렌더링할 수 있는 것은 직렬화해서 내보내고, 클라이언트 컴포넌트로 표시된 부분은 해당 공간을 플레이스홀더 형식으로 비워두고 나타낸다.
    - 브라우저는 이후에 이 결과물을 받아서 다시 역직렬화한 다음 렌더링을 수행한다
5. 브라우저가 컴포넌트 트리를 구성한다.
    - 트리를 구성했다면 구성한 트리를 바탕으로 렌더링해 브라우저의 DOM에 커밋한다.


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

- Next.js의 루트 컴포넌트는 각 페이지에 존재하는 page.js이고, 루트 컴포넌트는 무조건 서버 컴포넌트가 된다.
- layout.js도 마찬가지로 서버 컴포넌트로 작동한다.

### 새로운 fetch 도입과 getServerSideProps, getStaticProps, getInitialProps의 삭제

- 과거 Next.js의 서버 사이드 렌더링과 정적 페이지를 제공을 위해 getServerSideProps, getStaticProps, getInitialProps가 `/app` 디렉터리 내부에서 삭제됐다.
- 그 대신 모든 데이터 요청은 웹에서 제공하는 표준 API인 `fetch`를 기반으로 이뤄진다.

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

- 정적 라우팅에 대해서는 기본적으로 빌드 타임에 렌더링을 미리 해두고 캐싱해서 재사용할 수 있게끔 해두었다.
- 동적 라우팅에 대해서는 서버에 매번 요청이 올 때 마다 컴포넌트를 렌더링하도록 변경했다.

### 캐시와 mutating, 그리고 revalidating

- `fetch`의 기본 작동을 재정의해 `{next: {revalidate?: number | false}}`를 제공하는데, 이를 바탕으로 해당 데이터의 유효한 시간을 정해두고 이 시간이 지나면 다시 데이터를 불러와서 페이지를 렌더링하는 것이 가능하다.

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

- 과거 서버 사이드 렌더링은 페이지가 다 불러와질 때까지 사용자는 빈화면을 보게 됐었다.
- 이를 해결하기 위해 하나의 페이지가 다 완성될 때까지 기다리는 것이 아니라 HTML을 작은 단위로 쪼개서 완성되는 대로 클라이언트로 점진적으로 보내는 스트리밍이 도입됐다.
- 스트리밍을 활용하면 모든 데이터가 로드될 때까지 기다리지 않더라도 먼저 데이터가 로드되는 컴포넌트를 빠르게 보여주는 방법이 가능하다.

## 웹팩의 대항마, 터보팩의 등장(beta)

- `Rome, SWC, esbuild`의 공통점은 기존에 자바스크립트로 만들어지고 제공되던 기능을 Rust나 Go를 사용해 제공함으로써 자바스크립트 대비 월등히 뛰어난 성능을 보여준다는 것이다.
- 특히 SWC는 Next.js를 만든 Vercel에서 제공하는 도구로, Next.js에서 안정화가 완료되어 많은 프로젝트에서 바벨을 대신해 사용하고 있다.
- Next.js 13에서는 터보팩(Turbopack)이 출시됐다. 웹팩 대시 최대 700배, Vite 대비 최대 10배 빠르다고 하며 러스트 기반으로 작성되었다.
    - 아직 베타이다.

## 서버 액션(alpha)

- API를 굳이 생성하지 않더라도 함수 수준에서 서버에 직접 접근해 데이터 요청 등을 수행할 수 있는 기능이다.
- 서버 컴포넌트와 다르게, 특정 함수 실행 그 자체만들 서버에서 수행할 수 있다는 장점이 있다.
- 반드시 async 함수여야 한다.
- `'use server'` 키워드를 사용해야 서버 액션으로 간주한다.

### form의 action

- `<form/>` 태그에 action props를 추가해서 양식 데이터를 추가할 URI를 넘겨줄 수 있다. 
- 서버 액션으로 함수를 만들어 넘겨주면 submit 이벤트를 발생시키는 것을 클라이언트지만 실제로 함수 자체가 수행되는 것은 서버가 된다.
- url도 `/server-action/form`으로 요청되고, 페이로드에는 post 요청이 아닌 `ACTION_ID`라는 액션 구분자만 있는 것을 볼 수 있다.
- 서버 액션을 실행하면 클라이언트에서는 현재 라우트 주소와 `ACTION_ID`만 보내고 그 외에는 아무것도 실행하지 않는다.
    - 클라이언트 번들링 결과에는 포함되지 않고 서버에서만 실행되는 서버 액션을 만든 것이다.
- PHP와 같은 전통적인 서버 기반 웹 애플리케이션과 가장 큰 차이는 **페이지 새로고침 없이 수행된다**는 점이다.
- 데이터 스트리밍으로 이루어지기 때문에 클라이언트에서 새로운 결과를 받을 때까지 인터랙션을 구성할 수 있다.
- server mutation(서버에서의 데이터 수정)으로 실행할 수 있는 함수
    - `redirect`: 특정 주소로 리다이렉트 가능
    - `revalidatePath`: 해당 주소의 캐시를 즉시 업데이트. 새로운 데이터를 불러오는 역할.
    - `revalidateTag`: 캐시 태그는 fetch 요청 시에 추가 가능

### input의 submit과 image의 formAction

- `input type="submit"` 또는 `input type="image"`에 formAction prop으로도 서버 액션을 추가할 수 있다.

### startTransition과의 연동

- useTransition의 startTransition에서도 서버 액션 활용 가능하다.
- useTransition을 사용하면 page 단위의 `loading.jsx`를 사용하지 않고, isPending을 활용해 컴포넌트 단위의 로딩 처리가 가능해진다.

## 정리 및 주의사항

- 서버 컴포넌트는 파일 단위로 "use client"를 경계로 서버와 클라이언트 컴포넌트를 명확히 구분해야 하고, 나아가 라이브러리 또한 이 경계에 맞춰서 사용해야 하기 때문에 초기 개발 구조 설계에 큰 혼동이 있을 것으로 보인다.
- 리액트의 서버 컴포넌트는 이전에 없었던 완전히 새로운 패러다임이며 앞으로 리액트 생태계에 많은 변화를 가져올 것으로 보인다.

## 참고자료

- https://www.joshwcomeau.com/react/server-components/

# 회고

## Liked(좋았던 점)

- 웹 성능 지표에 대해 다시 한번 생각해볼 수 있어 좋았습니다.
- 서버 컴포넌트 사용하는 방식을 한 번에 볼 수 있었습니다.

## Learned(배웠던 점)

- 핵심 웹 지표로 꼽는 지표들에 대한 개념과 어떻게 개선할 수 있는 지를 알게 되었습니다.

## Lacked(아쉬운 점)

- 다음 시간에는 WebPageTest가 있는데 성능 테스트를 실습해 보아도 좋을 것 같습니다.
- 다음이 마지막 주차라 아쉽습니다..
