완벽 가이드 - form action

primav·2025년 3월 4일

React

목록 보기
32/35
post-thumbnail

📌 HTML - action 속성

기본 개념

<form> 태그의 action 속성은 폼을 제출했을 때 데이터를 전송할 서버의 URL을 지정하는 역할을 한다.

<form action="/submit" method="POST"> // 데이터를 `/submit` 경로로 보냄
  <input type="text" name="email" />
  <button type="submit">가입</button>
</form>

📌 리액트 - action 속성

리액트 19 부터는 서버 액션이라는 새로운 기능이 도입되면서, 기존의 event.preventDefault() 를 사용해서 JS 로 폼 제출을 처리하던 방식 외에, 폼의 action 속성에 직접 함수를 전달하는 방식이 가능해졌다.

기존 방식 (React 18 이하)

  • event.preventDefault()를 호출해서 기본 폼 제출 동작을 막아야 함
  • new FormData(event.target) 을 사용해서 데이터를 수동으로 가져옴
  • 폼 데이터를 서버에 fetch로 직접 전송해야 함
function handleSubmit(event) {
  event.preventDefault();
  const formData = new FormData(event.target);
  console.log(formData.get("email"));
}

<form onSubmit={handleSubmit}>
  <input type="text" name="email" />
  <button type="submit">가입</button>
</form>

새로운 방식 (React 19)

  • event.preventDefault() 가 필요 없음
    • action={signUpAction}을 사용하면 React가 자동으로 기본 동작을 중단하고 signUpAction 함수를 실행한다.
  • FormData 객체가 자동 전달됨
    • action={signUpAction} 처럼 이벤트 객체가 아니라, formData가 자동으로 함수에 전달된다.
  • 서버 액션과 연동 가능
    • React 19에서는 서버에서 직접 실행되는 함수(server actions)를 만들 수 있다.
    • 이 방식은 특히 Next.js 14 같은 프레임워크에서 유용하다.
      (서버에서 직접 실행되는 server action 과 조합)

❗️ formData.get("email") 와 같이 값을 가져오려면 <input id="email" type="email" name="email" /> 처럼 name이 꼭 필요하다!!

function signUpAction(formData) {
  const enteredEmail = formData.get("email");
  console.log(enteredEmail);
}

<form action={signUpAction}>
  <input type="text" name="email" />
  <button type="submit">가입</button>
</form>

기존 방식과 React 19 방식 비교

버전기존 방식 (onSubmit)React 19 방식 (action={})
제어 방식event.preventDefault() 필요기본적으로 폼 제출을 자동 처리
데이터 전달new FormData(event.target) 사용FormData가 자동으로 전달됨
서버 연동fetch API 사용 필요서버 액션과 직접 연동 가능
코드 가독성이벤트 핸들러 필요더 간결하고 직관적

여기서는 새로운 방식의 Form action 에 대해 알아보자!!

📌 useActionState

React 19에서 새롭게 도입된 useActionState는 폼의 action 속성에 연결된 함수의 상태를 관리하는 훅이다.

기존의 useStateuseReducer를 사용하지 않고도 폼 액션의 결과 (로딩 상태, 에러, 반환값 등)를 쉽게 관리할 수 있다는 장점이 있다.

useActionState(action, initialState)

리액트 공식 문서 : https://ko.react.dev/reference/react/useActionState

  • useActionState는 폼 액션의 결과를 기반으로 State를 업데이트할 수 있도록 제공하는 Hook
  • 기존의 폼 액션 함수와 초기 State를 전달받고, 폼에서 사용할 새로운 액션을 반환한다.
  • 폼을 마지막으로 제출했을 때 액션에서 반환되는 값으로, 아직 폼을 제출하지 않았다면 initialState로 설정된다.

반환값

세가지 값을 담은 배열을 반환한다.

  1. 현재 state - 첫 렌더링 시에는 initialState와 일치하며, 액션이 실행된 후에는 액션이 반환한 값과 일치한다.

  2. <form> 컴포넌트의 action Prop이나 폼 내부 <button> 컴포넌트의 formAction Prop에 전달할 수 있는 새 액션이다.

  3. 폼 액션이 대기 중인지 여부를 알려주는 isPending 플래그이다.

import { useActionState } from "react";

async function increment(previousState, formData) {
  return previousState + 1;
}

function StatefulForm({}) {
  const [state, formAction] = useActionState(increment, 0);
  return (
    <form>
      {state}
      <button formAction={formAction}>Increment</button>
    </form>
  );
}

기존 방식

  • 폼의 상태를 수동으로 관리해야 했음
  • fetch 요청을 직접 다뤄야 했음
const [loading, setLoading] = useState(false);
const [error, setError] = useState(null);

async function handleSubmit(event) {
  event.preventDefault();
  setLoading(true);
  setError(null);

  try {
    const formData = new FormData(event.target);
    const response = await fetch("/api/submit", {
      method: "POST",
      body: formData,
    });

    if (!response.ok) {
      throw new Error("Something went wrong");
    }
  } catch (err) {
    setError(err.message);
  } finally {
    setLoading(false);
  }
}

새로운 방식 (React19)

  • 자동으로 상태 관리 - useState 없이도 폼의 상태 추적 가능
    • state : 액션의 상태 (success, error, data 포함)
    • formAction : action={formAction} 을 설정하면 자동으로 signUpAction을 호출
const [state, formAction] = useActionState(signUpAction, null);
import { useActionState } from "react";

function signUpAction(formData) {
  const email = formData.get("email");
  console.log("Signing up with:", email);

  if (!email.includes("@")) {
    throw new Error("Invalid email format");
  }

  return { success: true };
}

export default function SignUpForm() {
  const [state, formAction] = useActionState(signUpAction, null);

  return (
    <form action={formAction}>
      <input type="email" name="email" required />
      <button type="submit">가입</button>

      {state?.error && <p style={{ color: "red" }}>{state.error.message}</p>}
      {state?.success && <p style={{ color: "green" }}>가입 완료!</p>}
    </form>
  );
}
방식기존 방식 (useState + fetch)React 19 (useActionState)
폼 제출 방식fetch 직접 사용form action={formAction} 사용
상태 관리useState로 loading, error, data 관리useActionState가 자동으로 관리
에러 처리try/catch 사용state.error 자동 관리
서버 연동fetch API 사용서버 액션과 직접 연동 가능

0개의 댓글