2025.7.19 토요일의 공부기록
React 19에서는 form + Server Action 패턴의 상태 관리를 위한 새로운 훅 useActionState
가 정식으로 도입되었다.
기존 Canary 빌드에서 제공되던 useFormState
는 React 19에서 이름과 기능이 확장되어 useActionState
로 변경되었으며, 서버 액션과 긴밀하게 연동된다.
useActionState
이란?useActionState
는 서버 액션(Form Action)의 결과를 기반으로 클라이언트 컴포넌트의 상태(state)를 업데이트 하도록 설계된 React 19 전용 Hook이다.
isPending
)를 함께 제공하여 UX를 단순화한다. useFormState
보다 공식·안정화된 API이다.🔗 React 공식 문서 – useActionState
https://ko.react.dev/reference/react/useActionState
const [state, formAction, isPending] =
useActionState(fn, initialState, permalink?);
매개변수 | 설명 | 필수 |
---|---|---|
fn | 서버 액션으로 동작할 비동기 함수 | 필수 |
initialState | Hook이 처음 가질 상태(기본값) | 필수 |
permalink | (선택) 고정된 URL(퍼머링크)을 서버 액션에 전달 | 아님 |
반환값 | 설명 |
---|---|
state | 서버 액션 처리 후 업데이트된 상태 |
formAction | <form action={formAction}> 로 연결되는 액션 함수 |
isPending | 액션이 실행 중인지 여부 (로딩 Boolean) |
useFormState
→ useActionState
변경사항React Canary (이전) | React 19 정식 (현재) |
---|---|
useFormState | useActionState |
DOM 기반 상태 전파 | 서버 액션 결과 기반 상태 전파 |
실험적 API | 안정화·공식 API |
아래 예시는 제품 업로드 폼에서 useActionState
를 사용해 서버 액션 결과를 처리하는 기본 패턴이다.
"use client";
import { useActionState } from "react";
import { uploadProduct } from "@/app/products/add/actions";
const initialState = { error: null };
export default function ProductForm() {
const [state, formAction, isPending] =
useActionState(uploadProduct, initialState);
return (
<form action={formAction}>
<input type="text" name="title" placeholder="제품명" required />
<input type="number" name="price" placeholder="가격" required />
<input type="file" name="photo" required />
<textarea name="description" placeholder="설명" required />
<button type="submit" disabled={isPending}>
{isPending ? "업로드 중..." : "제품 업로드"}
</button>
{state.error && <p style={{ color: "red" }}>
{JSON.stringify(state.error)}
</p>}
</form>
);
}
"use server";
import { z } from "zod";
export async function uploadProduct(prevState: any, formData: FormData) {
// Zod 검증 (예시)
const schema = z.object({
title: z.string().min(1),
price: z.coerce.number().positive(),
});
const result = schema.safeParse({
title: formData.get("title"),
price: formData.get("price"),
});
if (!result.success) {
return { error: result.error.flatten() };
}
// 성공 시 DB 저장 또는 다른 로직 수행
return { success: true };
}
useActionState
는 React 19 이상 버전에서만 동작한다. useFormState
를 사용 중이라면, React 19 업데이트 후 함수명을 변경해야 한다. fn
)는 항상 async 함수여야 하며, 첫 매개변수(prevState)로 기존 상태를 받을 수 있다.