React 19 RC의 useActionState와 Server Actions 실험

배경

React 19 RC가 공개되면서 useActionState(이전 useFormState에서 개명)와 Server Actions에 대한 관심이 높아졌다. 기존 프로젝트에서 폼 상태 관리를 위해 react-hook-form과 react-query를 조합해서 사용하고 있었는데, 새로운 방식이 실제로 얼마나 단순화할 수 있는지 확인해보고 싶었다.

기존 방식

const { register, handleSubmit } = useForm();
const mutation = useMutation({
  mutationFn: createPost,
  onSuccess: () => queryClient.invalidateQueries(['posts'])
});

const onSubmit = (data) => mutation.mutate(data);

useActionState 적용

Next.js 14 App Router 환경에서 Server Action과 함께 사용해봤다.

// app/actions.ts
'use server';

export async function createPost(prevState: any, formData: FormData) {
  const title = formData.get('title');
  // validation & DB insert
  return { success: true, message: '작성 완료' };
}

// app/components/PostForm.tsx
'use client';

import { useActionState } from 'react';

function PostForm() {
  const [state, formAction, isPending] = useActionState(createPost, null);

  return (
    <form action={formAction}>
      <input name="title" />
      <button disabled={isPending}>제출</button>
      {state?.message && <p>{state.message}</p>}
    </form>
  );
}

장단점

장점:

  • 클라이언트 코드가 확실히 줄어들었다
  • isPending 상태를 자동으로 제공
  • Progressive Enhancement 지원 (JS 없이도 동작)

단점:

  • TypeScript 타입 추론이 아직 불완전
  • 복잡한 validation은 여전히 zod 같은 라이브러리 필요
  • React 19가 아직 RC라 프로덕션 적용 리스크

결론

단순한 CRUD 폼에는 충분히 매력적인 방식이다. 하지만 복잡한 비즈니스 로직이 있는 폼은 여전히 기존 방식이 더 안정적이다. React 19 정식 릴리즈 이후 점진적으로 적용해볼 계획이다.