Next JS 치트 시트
2025.05.16 12:22:16
아래는 Next.js App Router에서의 Server Action 개념과 revalidateTag
, form action
과 함께 쓰는 예시를 정리한 내용이다.
1. Server Action이란?
- 서버에서 직접 실행되는 함수
- 클라이언트에서
form
,useFormState
,useTransition
등으로 호출 use server
디렉티브가 반드시 함수 내에 있어야 함- 서버 컴포넌트에서만 정의 가능
// app/actions/createPost.ts
'use server';
export async function createPost(formData: FormData) {
const title = formData.get('title');
const content = formData.get('content');
// DB에 저장 등 서버 로직
}
2. revalidateTag()
로 캐시 무효화하기
- 특정 fetch에 부여한
next: { tags: ['posts'] }
를 무효화해서 ISR 캐시를 다시 불러오게 함 - Server Action 내부에서만 호출 가능
import { revalidateTag } from 'next/cache';
'use server';
export async function createPost(formData: FormData) {
const title = formData.get('title');
const content = formData.get('content');
// DB 저장 로직 (예시)
await db.insert({ title, content });
// 'posts' 태그 캐시 무효화
revalidateTag('posts');
}
3. <form action={serverAction}>
사용 예시
예시 1: Form에서 바로 Server Action 호출
// app/posts/new/page.tsx
import { createPost } from '@/actions/createPost';
export default function NewPostPage() {
return (
<form action={createPost}>
<input name="title" placeholder="제목" required />
<textarea name="content" placeholder="내용" required />
<button type="submit">게시하기</button>
</form>
);
}
동작 흐름
- 사용자가
submit
createPost(formData)
서버에서 실행- 내부에서 DB 저장 및
revalidateTag('posts')
/posts
페이지가 다음 방문 시 새로운 데이터 반영
4. fetch
+ 캐시 태그 예시
// app/lib/fetchPosts.ts
export async function fetchPosts() {
return fetch(`${process.env.API_URL}/posts`, {
next: { tags: ['posts'] }, // ISR 캐시 태그
}).then(res => res.json());
}
- 위에서
revalidateTag('posts')
호출 시 이 fetch는 다음 요청에서 다시 실행됨 (ISR 재생성)
전체 흐름 요약
flowchart TD
A[사용자 form 제출] --> B[Server Action 실행]
B --> C[DB에 저장]
B --> D[revalidateTag('posts')]
D --> E[클라이언트 컴포넌트에서 posts 태그 캐시 무효화]
E --> F[다음 방문 시 fresh 데이터 fetch]
요약
항목 | 설명 |
---|---|
server action | 서버에서 실행되는 함수 ('use server' ) |
form action={함수} | 직접 해당 server action 호출 |
revalidateTag() | 캐시된 fetch를 강제로 무효화 |
fetch(..., next: { tags }) | ISR 태그 캐시 지정 |
Server Action의 동작 원리
React + Next.js가 Server Component를 통한 “함수 직렬화(serialization)”와 “form POST 처리”를 결합해, 함수 호출을 브라우저에서 서버로 위임하는 구조다.
1. Server Action의 실행 구조 요약
동작 흐름
- Server Component 안에 정의된 함수에
'use server'
선언 - Next.js는 이 함수를 reference로 변환
<form action={action}>
혹은action(formData)
호출 시,
→ 브라우저는 Next.js의 **특수 endpoint (/app/action
)**로 POST 요청 전송- Next.js 서버는 이 요청을 받아 → 해당 함수로 deserialize 및 실행
- 실행 결과는 서버에서 처리되고 클라이언트에 리디렉션 혹은 응답으로 전송됨
2. 실제로 내부에서 일어나는 것
예시 코드
'use server';
export async function createPost(formData: FormData) { ... }
Next.js가 빌드시 처리하는 방식
// 내부적으로 createPost는 이런 ID를 가지게 됨
__ACTION_ID__ = "app/actions/createPost.ts:createPost"
폼 제출 시
<form action="/app/action" method="POST">
<input type="hidden" name="__action_id__" value="app/actions/createPost.ts:createPost" />
...
</form>
서버에서 실행될 때
Next.js 내부에서:
// pseudo-code
if (req.url === '/app/action') {
const id = req.body.__action_id__;
const formData = req.body;
const fn = deserialize(id); // 해당 ID로 server action 복원
await fn(formData); // 서버에서 실행
}