Next.js 14부터 도입된 서버 액션(Server Actions)은 클라이언트에서 서버의 함수를 직접 호출할 수 있게 해주는 강력한 기능입니다.
이 기능을 활용하면 별도의 API 라우트를 만들지 않아도 폼 제출을 통해 서버에서만 실행되는 비동기 함수를 호출할 수 있어 훨씬 간단하고 직관적인 개발이 가능합니다.
💡 서버 액션 기본 사용법
export default function Page() {
const saveName = async (formData: FormData) => {
"use server";
const name = formData.get("name");
await saveDB({ name }); // ⓵ DB 함수 호출
await sql`INSERT INTO Names (name) VALUES (${name})`; // ⓶ SQL 직접 실행
};
return (
<form action={saveName}>
<input name="name" placeholder="이름을 알려주세요 ..." />
<button type="submit">제출</button>
</form>
);
}
- "use server" 지시자가 붙은 saveName 함수는 브라우저에서 호출되지만, Next.js 서버에서만 실행됩니다.
- <form>의 action 속성에 서버 액션 함수를 연결하면 폼 제출 시 해당 함수가 자동 호출됩니다.
- 브라우저에서 입력한 값은 FormData로 전달되며, 서버 액션 함수의 매개변수로 받을 수 있습니다.
🧪 실습 예제 - 리뷰 작성 폼
function ReviewEditor() {
async function createReviewAction() {
"use server";
console.log("server action called !");
}
return (
<section>
<form action={createReviewAction}>
<input name="content" placeholder="리뷰 내용" />
<input name="author" placeholder="작성자" />
<button type="submit">작성하기</button>
</form>
</section>
);
}
위와 같이 코드를 작성한 후, 두 개의 input에 값을 입력하고 ‘작성하기’ 버튼을 클릭해봅니다.
이제 브라우저의 Network 탭을 열어보면, 아래와 같이 request가 전송된 것을 확인할 수 있습니다.
그리고 서버 측 콘솔(VSCode의 터미널) 에는 아래와 같은 메시지가 출력됩니다.
다시 브라우저로 돌아가, 전송된 request의 내용을 좀 더 자세히 들여다보겠습니다.
Network > Headers 탭을 살펴보면, Request URL이 localhost:3000/book/1로 설정되어 있어, 요청이 Next.js 서버로 전송된 것을 확인할 수 있습니다. 또한 Request Method는 POST 방식으로 지정되어 있습니다.
조금 더 아래로 내려가면, Request Headers > Next-Action 항목에서 특정 해시값이 자동으로 포함된 것도 볼 수 있습니다.
서버 액션은 컴파일 시, 고유한 해시값을 가지는 API로 자동 설정되기 때문에 브라우저는 이 해시값을 Next-Action이라는 이름의 헤더에 포함시켜 요청하게 됩니다.
이번엔 Network > Payload 탭으로 이동해보겠습니다.
이곳에서는 실제로 서버로 전송된 데이터를 확인할 수 있습니다.
- action_id : 호출하려는 서버 액션의 해시값 (자동 설정됨)
이러한 값들은 Form Data 형식으로 묶여 서버에 전달되며, 서버 액션 함수의 매개변수로 자동 전달됩니다.
서버 액션 함수에서 이 데이터를 직접 받아보도록 코드를 수정해보겠습니다.
async function createReviewAction(formData: FormData) {
"use server";
console.log("server action called !");
console.log(formData);
}
이제 브라우저에서 content와 author에 각각 123을 입력하고 작성하기 버튼을 눌러보면,
서버 콘솔에 FormData 객체가 출력됩니다.
이제 전달받은 데이터를 꺼내서 활용해보겠습니다.
async function createReviewAction(formData: FormData) {
"use server";
const content = formData.get("content");
const author = formData.get("author");
console.log(content, author);
}
formData.get() 메서드를 사용하면 key 값을 기준으로 원하는 데이터를 꺼낼 수 있습니다.
콘솔을 통해 입력값이 정상적으로 전달되었는지 확인할 수 있습니다.
다시 content와 author에 각각 123을 입력한 뒤 폼을 제출해보면,
콘솔에 아래와 같이 값이 잘 출력됩니다.
⚠️ 주의사항
content나 author에 마우스를 올려보면, 변수의 타입이 FormDataEntryValue | null로 추론됩니다.
FormDataEntryValue는 string 또는 File 타입을 의미하기 때문에, 문자열만 사용할 경우에는 타입을 명확히 지정해주는 것이 좋습니다.
이럴 때는 toString() 메서드를 사용하여 문자열로 변환해주면 안전합니다.
const content = formData.get("content")?.toString();
const author = formData.get("author")?.toString();
이렇게 작성하면 해당 값이 존재할 때에만 문자열로 변환되며,
마우스를 올려보면 변수의 타입이 string | undefined로 정확하게 추론된 것도 확인할 수 있습니다.
'📍 프로그래밍 언어 > Next.js' 카테고리의 다른 글
[ Next.js ] 스트리밍 (Streaming) - loading.tsx와 Suspense 활용하기 (9) | 2025.06.26 |
---|---|
[ Next.js ] 클라이언트 라우터 캐시와 레이아웃 최적화 원리 (1) | 2025.06.26 |
[ Next.js ] 라우트 세그먼트(Route Segments): dynamic 옵션 정리 (2) | 2025.06.25 |
[ Next.js ] 캐싱 전략 이해하기: 풀 라우트 캐시(Full Route Cache) (1) | 2025.06.25 |
[ Next.js ] 중복 API 요청을 줄이는 방법: Request Memoization (1) | 2025.06.17 |