useActionState(useFormState)

Odyssey·2025년 2월 7일

Next.js_study

목록 보기
29/58
post-thumbnail

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를 사용하면 서버 액션의 실행 결과를 자동으로 상태에 반영할 수 있어 코드가 더욱 간결해진다.
  • React 19부터 useFormState 대신 useActionState를 사용해야 한다!

그럼, 왜 React 19에서 useActionState로 변경되었을까?

🔍 useActionState의 추가적인 장점

기능useFormState (구버전)useActionState (최신)
React 지원 버전React 18React 19
서버 액션 실행✅ 지원✅ 지원
prevState 활용 가능✅ 가능✅ 가능
로딩 상태 (isPending) 제공❌ 없음 (useState 필요)✅ 기본 제공
이름이 직관적useFormState (폼 한정)useActionState (폼 외에도 확장 가능)

🔑 React 19에서 useActionState로 변경된 이유

  1. 폼뿐만 아니라, 일반적인 서버 액션에도 사용할 수 있도록 네이밍 변경
    useFormState폼(form)에만 제한된 느낌이었지만,
    useActionState서버 액션 전반에 사용 가능하도록 개선됨.

  2. 로딩 상태 (isPending)를 기본 제공
    useFormState에서는 별도의 useState()를 사용해야 했지만,
    useActionState에서는 isPending을 기본 제공하여 더 간결한 코드 작성 가능.

  3. 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: "" })를 사용하여 폼 제출 상태를 자동으로 관리.
  • formActionform 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 공식 문서를 참고하자! 🚀

0개의 댓글