Skip to content

Commit

Permalink
Merge pull request #73 from prgrms-web-devcourse/#11/효중
Browse files Browse the repository at this point in the history
  • Loading branch information
hyoribogo authored Feb 22, 2024
2 parents bf7201f + 497b6e0 commit b17188c
Showing 1 changed file with 117 additions and 0 deletions.
117 changes: 117 additions & 0 deletions [11장] Next.js 13과 리액트 18/효중.md
Original file line number Diff line number Diff line change
Expand Up @@ -391,3 +391,120 @@ fetch 옵션에 따른 작동 방식을 정리하면 다음과 같다.
- 직접적으로 Suspense를 사용한다.

Loading이 Suspense를 기반으로 만들어진 Next의 규칙이기 때문에 직접 Suspense를 사용하는 것도 동일한 효과를 낼 수 있따.

## 터보팩의 등장

SWC는 Next js를 만든 vercel에서 제공하는 도구로 12버전부터 안정화가 완료되어 공식적으로 사용할 것을 권장하고 있다. 13버전에서는 터보팩이 새로 출시되었다. 터보팩은 vite 대비 최대 10배 빠르다고 하며, 13.4버전부터 터보팩도 베타로 전환되었다.

## 서버 액션

이 기능은 API를 굳이 생성하지 않아도 함수 수준에서 서버에 접근해 데이터 요청 등을 수행할 수 있는 기능이다. 서버 컴포넌트와 다르게 특정 함수 실행 그 자체만을 서버에서 수행할 수 있다는 장점이 있다.

서버 액션을 만드려면 함수 내부 또는 상단에 클라이언트 컴포넌트의 선언과 비슷하게 'use server'지시어를 선언해야 한다. 그리고 이 함수는 반드시 async여야만 한다.

```ts
async function serverAction(){
'use server'
//서버에 바로 접근하는 코드
}

//이 파일 내부의 모든 내용이 서버 액션으로 간주된다.
'use server'
export async function myAction(){
//서버에 바로 접근하는 코드
}
```

form은 HTML에서 양식을 보낼 때 사용한느 코드로 action props를 추가해서 이 양식 데이터를 처리할 URI를 넘길 수 있다.

```ts
export default function Page(){
async function handleSubmit(){
'use server'

const res = await fetch('.../',{
method:'post',
body:JSON.stringify({
title:'foo',
body:'bar'
}),
headers:{
'Content-type':'application/json'
}
})

const result = await res.json()

}
return (
<form action = handleSubmit>
<button>요청</button>
</form>
)
}
```
form의 action에 서버 액션을 만들어 넘겨주었다. 이 함수는 이벤트를 발생시키는 것은 클라이언트지만 실제로 함수 자체가 수행되는 것은 서버가 된다. server-action/form으로 요청이 수행되고 페이로드에서는 post요청이 아닌 ACTION_ID라는 액션의 구분자만 담기게 된다.

서버 액션을 실행하면 클라이언트에서는 현재 라우트 주소와 ACTION_ID를 보내고 그 외에는 아무것도 실행하지 않는 것을 알 수 있다. 서버에서는 요청받은 라우트 주소와 ACTION_ID를 기준으로 실행해야 할 내용을 찾고 서버에서 직접 실행한다. 이를 위해 'use server'로 선언된 내용은 빌드 시점에 클라이언트에서 분리하고 서버로 옮김으로써 클라이언트 번들링 결과에는 포함되지 않는다.

```ts
import kv from '@vercel/kv'

import {revalidatePath} from 'next/cache'

interface Data {
name : string,
age: number
}

export default async function Page({params} : {params: {id:string}}){
async function handleSubmit(formData : FormData) {
'use server'

const name = formData.get('name')
const age = formData.get('age')

await kv.set(key,{
name,
age
})

revalidatePath(`/server-action.form/${params.id}`)
}
return (
<>
<form action = {handleSubmit}>
<label htmlFor = "name">이름</label>
<input type = "text" id = "name" name = "name" />
<label htmlFor = "age">나이</label>
<input type = "number" id = "age" name = "age" />
<button>Submit</button>
</form>
</>
)
}
```

Page컴포넌트는 서버 컴포넌트로 form태그에 서버 액션인 handleSubmit을 추가해 formData를 기반으로 데이터를 가져와 데이터베이스(kv)를 업데이트한다. 그리고 업데이트가 마무리되면 마지막으로 revalidatePath을 통해 해당 주소의 캐시를 갱신해 컴포넌트를 다시 렌더링한다.

handleSubmit의 revalidatePath을 주목하자. 이는 인수로 넘겨받은 경로의 캐싱을 초기화해서 해당 URL에서 즉시 새로운 데이터를 불러오는 역할을 한다. Next에서는 이를 server mutation(서버에서의 데이터 수정)이라고 하는데 server mutation으로 실행할 수 있는 함수는 다음과 같다.

- redirect : 특정 주소로 리다이렉트 할 수 있는 함수이다. 서버 컴포넌트, 라우트 핸들러, 그리고 서버 액션에서 사용될 수 있습니다.
- revalidatePath : 해당 주소의 캐시를 즉시 업데이트 한다.
- revalidateTag : 캐시 태그는 fetch 요청 시에 다음과 같이 추가한다. 이렇게 태그를 추가하면 여러 fetch 요청을 특정 태그 값으로 구분하며 revalidateTag를 사용하면 특정 태그가 추가된 fetch 요청을 초기화한다.

```ts
fetch('...', {
next : {
tags : ['']
}
})
```

### 서버 액션 사용시 주의할 점

- 서버 액션은 클라이언트 컴포넌트 내에서 정의될 수 없다. 서버 액션을 'use client'가 선언되어 있는 컴포넌트 내에서 쓰면 에러가 발생한다.

- 서버 액션을 import하는 것 뿐 아니라, props로 서버 액션을 클라이언트 컴포넌트로 넘기는 것 또한 불가능하다.

https://github.com/gabrielelpidio/next-infinite-scroll-server-actions

0 comments on commit b17188c

Please sign in to comment.