
2025.2.8 토요일의 공부기록
useActionState란?useActionState는 폼 액션의 결과를 기반으로 상태를 업데이트할 수 있도록 제공하는 React 훅이다.
이전에는 useFormState로 불렸으나, React 19 버전부터 useActionState로 변경되었다.
🔗 공식 문서:
useActionState vs 기존 방식 비교| 방식 | 기존 방식 (useState + fetch) | 최신 방식 (useActionState) |
|---|---|---|
| 상태 관리 | useState()로 응답을 직접 관리 | useActionState()에서 자동 관리 |
| 데이터 전송 방식 | fetch("/api")로 요청 | useActionState()에서 서버 액션 실행 |
| 코드 간결성 | useEffect, useState, fetch 필요 | useActionState(fn, initialState)로 간단하게 처리 |
📌 결론:
useActionState를 사용하면 서버 액션의 실행 결과를 자동으로 상태에 반영할 수 있어 코드가 더욱 간결해진다. useFormState 대신 useActionState를 사용해야 한다!useActionState로 변경되었을까?useActionState의 추가적인 장점| 기능 | useFormState (구버전) | useActionState (최신) |
|---|---|---|
| React 지원 버전 | React 18 | React 19 |
| 서버 액션 실행 | ✅ 지원 | ✅ 지원 |
prevState 활용 가능 | ✅ 가능 | ✅ 가능 |
로딩 상태 (isPending) 제공 | ❌ 없음 (useState 필요) | ✅ 기본 제공 |
| 이름이 직관적 | useFormState (폼 한정) | useActionState (폼 외에도 확장 가능) |
useActionState로 변경된 이유폼뿐만 아니라, 일반적인 서버 액션에도 사용할 수 있도록 네이밍 변경
→ useFormState는 폼(form)에만 제한된 느낌이었지만,
→ useActionState는 서버 액션 전반에 사용 가능하도록 개선됨.
로딩 상태 (isPending)를 기본 제공
→ useFormState에서는 별도의 useState()를 사용해야 했지만,
→ useActionState에서는 isPending을 기본 제공하여 더 간결한 코드 작성 가능.
Next.js와의 연계성 강화
→ Next.js의 최신 Server Actions 패턴과 더 직관적으로 연결됨.
useActionState 기본 사용법server-actions.ts)"use server";
export async function handleLogin(prevState: any, formData: FormData) {
const email = formData.get("email")?.toString();
const password = formData.get("password")?.toString();
if (!email || !password) {
return { success: false, message: "이메일과 비밀번호를 입력하세요." };
}
if (email === "test@example.com" && password === "1234") {
return { success: true, message: "로그인 성공!" };
} else {
return { success: false, message: "이메일 또는 비밀번호가 올바르지 않습니다." };
}
}
📌 설명:
"use server";를 사용하여 이 함수가 서버에서 실행됨.prevState를 사용하여 이전 상태를 기반으로 새로운 상태를 반환.useActionState로 폼 상태 관리 (login.tsx)"use client";
import { useActionState } from "react";
import { handleLogin } from "@/server-actions";
export default function LogIn() {
const [state, formAction, isPending] = useActionState(handleLogin, { success: null, message: "" });
return (
<div className="flex flex-col gap-10 py-8 px-6">
<h1 className="text-2xl">로그인</h1>
<form action={formAction} className="flex flex-col gap-3">
<input name="email" type="email" placeholder="Email" className="border p-2" required />
<input name="password" type="password" placeholder="Password" className="border p-2" required />
<button type="submit" disabled={isPending} className="bg-blue-500 text-white px-4 py-2 rounded-md">
{isPending ? "Logging in..." : "Log In"}
</button>
</form>
{state.message && (
<p className={state.success ? "text-green-500" : "text-red-500"}>
{state.message}
</p>
)}
</div>
);
}
📌 설명:
useActionState(handleLogin, { success: null, message: "" })를 사용하여 폼 제출 상태를 자동으로 관리.formAction을 form action={formAction}에 전달하여 서버 액션을 자동으로 실행.isPending을 사용하여 폼 제출 중 버튼을 비활성화.state.message를 출력하여 로그인 결과 메시지를 표시.useActionState에서 API 응답 활용"use client";
import { useRouter } from "next/navigation";
import { useActionState } from "react";
import { handleLogin } from "@/server-actions";
export default function LogIn() {
const router = useRouter();
const [state, formAction, isPending] = useActionState(handleLogin, { success: null, message: "" });
if (state.success) {
router.push("/dashboard"); // 로그인 성공 시 대시보드로 이동
}
return (
<div className="flex flex-col gap-10 py-8 px-6">
<h1 className="text-2xl">로그인</h1>
<form action={formAction} className="flex flex-col gap-3">
<input name="email" type="email" placeholder="Email" className="border p-2" required />
<input name="password" type="password" placeholder="Password" className="border p-2" required />
<button type="submit" disabled={isPending} className="bg-blue-500 text-white px-4 py-2 rounded-md">
{isPending ? "Logging in..." : "Log In"}
</button>
</form>
{state.message && (
<p className={state.success ? "text-green-500" : "text-red-500"}>
{state.message}
</p>
)}
</div>
);
}
📌 설명:
router.push("/dashboard")를 사용해 자동으로 대시보드 페이지로 이동.| ✅ 기능 | 🛠 설명 |
|---|---|
| 폼 상태 자동 관리 | useActionState(handleLogin, initialState) |
| 폼 제출 시 버튼 비활성화 | isPending 사용 (disabled={isPending}) |
| 서버 응답 활용 | state.message, state.success 값 활용 |
| 로그인 성공 후 페이지 이동 | router.push("/dashboard") 사용 |
📌 더 자세한 내용은 React 공식 문서를 참고하자! 🚀