티스토리 뷰

웹 개발의 흐름은 늘 '복잡함'에서 '단순함'으로 회귀하곤 합니다. 과거에는 HTML Form을 던지면 서버가 받는 단순한 구조였다가, SPA(Single Page Application) 시대에 접어들며 클라이언트에서 데이터를 가공하고 API 엔드포인트를 호출하는 복잡한 과정을 거치게 되었죠.
Next.js에서 도입된 Server Actions는 이 복잡한 중간 단계를 제거합니다. 별도의 API Route를 만들지 않고도 클라이언트의 이벤트를 서버 함수와 직접 연결하는 이 기술이 왜 현대 웹 생태계의 '게임 체인저'로 불리는지 심도 있게 살펴보겠습니다.
1. 핵심 개념 설명 (Deep Dive)
작동 원리: 브릿지 없는 데이터 전송
Server Actions는 클라이언트에서 호출하지만 실제로는 서버에서 실행되는 비동기 함수입니다. 이전에는 폼 제출을 위해 fetch나 axios를 사용해 특정 URL로 POST 요청을 보내고 리스폰스를 기다려야 했습니다. 하지만 Server Actions를 사용하면 함수 자체가 하나의 엔드포인트 역할을 수행합니다.
일상적인 비유: 무전기와 유선 전화
- 기존 API 방식 (유선 전화): 전화를 걸고, 상대방이 받을 때까지 기다린 뒤, 내 신원을 밝히고 용건을 말해야 합니다. (엔드포인트 설정, JSON 직렬화, 페칭 로직 필요)
- Server Actions (무전기): 버튼 하나만 누르면 서버(상대방)와 즉시 연결되어 메시지가 전달됩니다. 복잡한 연결 과정은 시스템 내부에서 알아서 처리해주죠.
2. 풍부한 실전 예제 (Hands-on)
단순한 이름 입력 폼이 아닌, 실제 이커머스에서 활용될 법한 "제품 재고 업데이트 시스템" 예제를 통해 구현 방법을 알아보겠습니다.
단계 1: 서버 액션 정의하기
먼저 서버에서만 실행될 로직을 분리하여 작성합니다. use server 지시어가 이 함수의 실행 환경을 결정합니다.
// actions/inventory.js
"use server";
import { revalidatePath } from "next/cache";
/**
* 재고 수량을 업데이트하는 서버 액션
* @param {FormData} formData - 폼에서 전달된 데이터
*/
export async function updateStock(formData) {
const productId = formData.get("productId");
const quantity = formData.get("quantity");
// 1. 비즈니스 로직: 실제 데이터베이스 업데이트 (예시)
console.log(`DB 작업 시작: 제품 ID ${productId}의 재고를 ${quantity}개로 변경합니다.`);
// 데이터베이스 연결 및 업데이트 로직이 여기에 위치합니다.
// await db.product.update({ where: { id: productId }, data: { stock: quantity } });
// 2. 캐시 갱신: 데이터가 변했으므로 페이지를 새로 고침하여 사용자에게 최신 상태를 보여줍니다.
revalidatePath("/inventory");
return { success: true, message: "재고가 성공적으로 업데이트되었습니다." };
}
단계 2: 클라이언트 컴포넌트 구성
별도의 onSubmit 핸들러나 상태 관리가 필요 없습니다. 폼의 action 속성에 위에서 만든 함수를 연결하기만 하면 됩니다.
// components/StockForm.js
import { updateStock } from "@/actions/inventory";
export default function StockForm({ productId }) {
return (
<form action={updateStock} className="stock-form">
{/* 제품 ID는 사용자에게 보이지 않게 hidden 필드로 처리 */}
<input type="hidden" name="productId" value={productId} />
<div className="input-group">
<label htmlFor="quantity">조정 수량</label>
<input
type="number"
id="quantity"
name="quantity"
required
placeholder="수량을 입력하세요"
/>
</div>
<button type="submit">재고 업데이트 반영</button>
</form>
);
}
트러블슈팅 팁
- 데이터 타입 문제: formData.get()으로 가져오는 값은 기본적으로 **문자열(String)**입니다. 숫자가 필요한 로직이라면 Number()를 통해 반드시 형변환을 거쳐야 에러를 방지할 수 있습니다.
- 로딩 상태 처리: 폼 제출 중 버튼을 비활성화하고 싶다면 React의 useFormStatus 훅을 활용하세요. 이 훅은 해당 폼의 상태를 자동으로 감지합니다.
3. 장단점 및 고려사항 (Trade-offs)
Server Actions는 강력하지만 모든 상황에서 정답은 아닙니다.
장점
- 코드 감소: API Route를 정의하는 보일러플레이트 코드가 사라집니다.
- 점진적 향상: 자바스크립트가 로드되기 전에도 브라우저 기본 기능을 통해 폼 전송이 가능해집니다.
- 강력한 타입 안전성: 서버와 클라이언트 간의 데이터 규약을 맞추기가 훨씬 수월합니다.
단점 및 한계
- 서버 리소스 점유: 모든 액션이 서버에서 실행되므로, 단순한 UI 변경 로직까지 서버 액션으로 처리하면 불필요한 서버 부하를 줄 수 있습니다.
- Next.js 종속성: 프레임워크에 강하게 결합되므로 나중에 다른 환경으로 이전할 때 코드 수정이 많이 필요할 수 있습니다.
4. 결론 및 요약
Server Actions는 클라이언트와 서버 사이의 벽을 허물어 개발 생산성을 비약적으로 높여줍니다. 특히 데이터 쓰기(Write) 작업과 페이지 갱신(Revalidation)이 동시에 일어나는 폼 처리에서 그 진가를 발휘합니다.
단순히 "기술이 새로우니까" 쓰는 것이 아니라, 내 프로젝트에서 API 레이어를 관리하는 비용이 얼마나 큰지를 먼저 따져보세요. 만약 단순 CRUD가 반복되는 프로젝트라면 Server Actions는 여러분의 퇴근 시간을 앞당겨줄 최고의 도구가 될 것입니다.
'Frontend > Next.js' 카테고리의 다른 글
| Metadata API를 활용한 동적 SEO(검색 엔진 최적화) 설정 (0) | 2026.03.13 |
|---|---|
| Route Handlers를 통한 커스텀 API 엔드포인트 생성 (0) | 2026.03.13 |
| Dynamic Routes: 동적 파라미터([id]) 처리와 상세 페이지 (0) | 2026.03.13 |
| Error Handling: error.js와 not-found.js 구현 (0) | 2026.03.13 |
| Loading UI와 Suspense를 활용한 사용자 경험 개선 (0) | 2026.03.12 |
- Total
- Today
- Yesterday
- on-device ai
- CSS
- react
- 스마트안경
- Javascript
- 구글
- sLLM
- Rag
- 멀티모달
- CSR
- HBM
- 웹기초
- Nextjs
- 엣지컴퓨팅
- TypeScript
- MSA
- LLM
- java
- SSR
- prompt engineering
- 협력
- It용어
- 카카오
- HTML
- AI
| 일 | 월 | 화 | 수 | 목 | 금 | 토 |
|---|---|---|---|---|---|---|
| 1 | 2 | 3 | 4 | |||
| 5 | 6 | 7 | 8 | 9 | 10 | 11 |
| 12 | 13 | 14 | 15 | 16 | 17 | 18 |
| 19 | 20 | 21 | 22 | 23 | 24 | 25 |
| 26 | 27 | 28 | 29 | 30 |