React 19에서는 <form action={함수}>에 함수를 바로 넘길 수 있고, useActionState가 그 액션의 대기 상태와 마지막 결과를 한 훅으로 관리한다. useState + onSubmit + 로딩 플래그로 짜던 패턴을 대체한다.
'use client'
const [state, formAction, isPending] = useActionState(updateName, null)
// updateName(prevState, formData) — 서버 함수여도 된다
<form action={formAction}>
<input name="name" disabled={isPending} />
<button disabled={isPending}>저장</button>
{state?.error && <p>{state.error}</p>}
</form>- 액션은 이전 상태와
FormData를 받아 다음 상태(에러 메시지, 결과)를 반환한다. 서버 쪽 검증 결과를 그대로 화면에 보여 주기 좋다(서버 함수와 서버 액션) - form action으로 넘긴 함수는 자동으로 transition 안에서 실행된다(useTransition)
- 점진적 향상(Progressive Enhancement): 서버 액션과 함께 쓰면 JS(JavaScript)가 로드되기 전에도 폼이 제출되고, 하이드레이션 전 제출은 나중에 다시 실행된다(하이드레이션)
useFormStatus: 폼 안쪽의 자식 컴포넌트(제출 버튼)가 props를 받지 않고도 상위 폼의 제출 상태를 읽는다useOptimistic: 서버 확정 전에 결과를 미리 화면에 반영하고, 실패하면 되돌린다
입력값을 state로 들지 않는 비제어 입력과 잘 맞는다. 같은 일을 클라이언트 캐시 쪽에서 하는 방법은 TanStack Query의 useMutation이다.