🧭 들어가며
작년 12월에, React 19는 드디어 공식 프리뷰(알파)를 통해 여러 신기능들을 공개했습니다.
그중에서도 특히 주목할 만한 기능은 폼 상태 처리와 서버 액션에 대한 새로운 접근 방식입니다.
서버와 클라이언트가 자연스럽게 협업할 수 있도록 만들어주는 훅,
바로 useFormState, useFormStatus, useActionState입니다.
이번 글에서는 이 새로운 훅들이 어떤 문제를 해결해주는지,
그리고 어떻게 사용할 수 있는지를 예제와 함께 살펴보도록 하겠습니다.
🎯 기존의 문제점: React에서 폼을 다룰 때 생기는 일들
React에서는 일반적으로 폼 상태를 이렇게 다룹니다:
- useState로 입력값을 관리하고
- onChange, onSubmit으로 이벤트를 제어하며
- 서버 요청은 fetch나 axios로 따로 수행하고
- 로딩, 에러, 성공 여부를 직접 상태로 만들어 처리함
복잡하죠? 특히 상태가 많아질수록 유지보수가 어려워집니다.
React 19는 이 과정을 더 직관적이고 선언적으로 바꾸고자 합니다.
🧪 1. useFormState: 서버 액션과 상태를 연결
📌 기본 구조
const [state, formAction] = useFormState(serverAction, initialState);
- serverAction: 서버에서 실행되는 함수 (서버 액션)
- initialState: 초기 상태 (예: { message: "" })
- state: 서버에서 반환한 최신 상태
- formAction: <form action={formAction}>에 연결
✅ 예시 코드
// app/actions.ts
export async function login(prevState: any, formData: FormData) {
const username = formData.get("username");
const password = formData.get("password");
if (username !== "admin" || password !== "1234") {
return { message: "로그인 실패" };
}
return { message: "로그인 성공" };
}
// app/page.tsx
'use client';
import { useFormState } from 'react-dom';
import { login } from './actions';
export default function LoginForm() {
const [state, formAction] = useFormState(login, { message: '' });
return (
<form action={formAction}>
<input name="username" placeholder="Username" />
<input name="password" type="password" placeholder="Password" />
<button type="submit">로그인</button>
<p>{state.message}</p>
</form>
);
}
📌 핵심 포인트:
- 별도 useState 없이도 서버 반환 상태 관리 가능
- 폼 전송 결과는 자동으로 state에 반영됨
🧭 2. useFormStatus: 폼 상태를 쉽고 간결하게 확인
useFormStatus는 폼 전송 중인지, 성공했는지 등을 간단히 확인할 수 있는 훅입니다.
'use client';
import { useFormStatus } from 'react-dom';
function SubmitButton() {
const { pending } = useFormStatus();
return (
<button type="submit" disabled={pending}>
{pending ? '로그인 중...' : '로그인'}
</button>
);
}
✅ 장점:
- 별도로 로딩 상태 만들지 않아도 됨
- 현재 전송 중인지 여부만으로 UX 향상 가능
⚙️ 3. useActionState: 폼 없이 서버 액션과 상태 연동
useFormState는 <form>과 함께 사용해야 하지만,
useActionState는 버튼 클릭 등 다른 인터랙션에도 사용 가능합니다.
'use client';
import { useActionState } from 'react-dom';
import { doSomething } from './actions';
export default function SomeComponent() {
const [state, action] = useActionState(doSomething, { count: 0 });
return (
<div>
<button onClick={() => action()}>+1</button>
<p>Count: {state.count}</p>
</div>
);
}
- 서버 액션에서 count를 1씩 증가시켜 반환할 수 있음
- 별도 이벤트 핸들러 없이 상태 반영 가능
💡 왜 이게 중요한가?
- ✅ 더 선언적인 폼 처리
- ✅ 클라이언트-서버의 자연스러운 연결
- ✅ 로딩/성공/실패 상태 관리 간소화
- ✅ 코드량 감소 + 명확한 책임 분리
결국 이 흐름은 React 19가 추구하는 **서버 중심의 아키텍처(Server-first)**와 맞닿아 있어요.
바로 직전 포스트인 RSC와 연관이 있는..! 미래 지향적인 변화의 흐름이라고 볼 수 있습니다.
클라이언트는 최소한의 UI만 책임지고, 주요 로직은 서버에서 다룰 수 있게 됩니다.
🚨 현재 상태 및 주의점
- React 19는 아직 알파(Alpha) 버전이에요.
- Next.js 14의 App Router 환경에서 주로 실험 가능
- 서버 액션은 서버 컴포넌트 안에서만 정의 가능
실무 도입은 아직 이르지만, 실험 프로젝트나 학습용으론 매우 추천할 만합니다!
✍️ 마무리하며
React 19의 새 훅들은 단순한 API 추가가 아닙니다.
**"클라이언트-서버의 경계를 허물고, 선언적으로 동작하는 React의 미래"**에 대한 방향성이 담겨 있어요.
폼 상태를 일일이 핸들링하며 고생했던 프론트엔드 개발자들에게는 아주 반가운 소식인 것 같습니다.
🔗 참고 자료
'React' 카테고리의 다른 글
| [React] 📁 프로젝트 폴더 구조, 어떻게 구성해야 할까? (0) | 2025.04.13 |
|---|---|
| 🐻 React + Zustand로 간단하고 가벼운 전역 상태 관리하기 (0) | 2025.04.12 |
| [React]🔥React Server Components(RSC)의 등장과 미래 (0) | 2025.04.12 |
| [JavaScript]🔍화살표 함수(Arrow Function) vs function 키워드 차이점 (0) | 2025.04.11 |
| [React]🔑배열의 index를 key로 사용하면 안되는 이유 (0) | 2025.04.11 |