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 속성에 직접 함수를 전달하는 방식이 가능해졌다.
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>
event.preventDefault() 가 필요 없음action={signUpAction}을 사용하면 React가 자동으로 기본 동작을 중단하고 signUpAction 함수를 실행한다.FormData 객체가 자동 전달됨action={signUpAction} 처럼 이벤트 객체가 아니라, formData가 자동으로 함수에 전달된다.server actions)를 만들 수 있다.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>
| 버전 | 기존 방식 (onSubmit) | React 19 방식 (action={}) |
|---|---|---|
| 제어 방식 | event.preventDefault() 필요 | 기본적으로 폼 제출을 자동 처리 |
| 데이터 전달 | new FormData(event.target) 사용 | FormData가 자동으로 전달됨 |
| 서버 연동 | fetch API 사용 필요 | 서버 액션과 직접 연동 가능 |
| 코드 가독성 | 이벤트 핸들러 필요 | 더 간결하고 직관적 |
여기서는 새로운 방식의 Form action 에 대해 알아보자!!
React 19에서 새롭게 도입된 useActionState는 폼의 action 속성에 연결된 함수의 상태를 관리하는 훅이다.
기존의 useState나 useReducer를 사용하지 않고도 폼 액션의 결과 (로딩 상태, 에러, 반환값 등)를 쉽게 관리할 수 있다는 장점이 있다.
useActionState(action, initialState)
리액트 공식 문서 : https://ko.react.dev/reference/react/useActionState
useActionState는 폼 액션의 결과를 기반으로 State를 업데이트할 수 있도록 제공하는 HookState를 전달받고, 폼에서 사용할 새로운 액션을 반환한다.initialState로 설정된다.세가지 값을 담은 배열을 반환한다.
현재 state - 첫 렌더링 시에는 initialState와 일치하며, 액션이 실행된 후에는 액션이 반환한 값과 일치한다.
<form> 컴포넌트의 action Prop이나 폼 내부 <button> 컴포넌트의 formAction Prop에 전달할 수 있는 새 액션이다.
폼 액션이 대기 중인지 여부를 알려주는 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);
}
}
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 사용 | 서버 액션과 직접 연동 가능 |