React
요약
useActionState는 폼 제출과 함께 발생하는 상태 관리 로직을 하나의 Hook으로 응축한 React 19의 핵심 기능이다.
기존처럼 onSubmit 내부에서 loading → 요청 → 응답 → loading 해제를 직접 제어하지 않아도 되고, 요청 상태·응답 데이터·에러를 선언적으로 관리할 수 있다.
특히 Next.js App Router + Server Actions 환경에서는 서버에서 바로 실행되는 액션과 자연스럽게 결합되어, 코드 복잡도는 줄이고 성능과 가독성은 크게 개선된다.
정의
useActionState는 폼 액션(action) 을 중심으로
- 요청 중 상태 (
pending) - 서버 또는 클라이언트 액션의 결과 값 (
state) - 액션을 실행하는 함수 (
action)
를 하나의 Hook으로 관리할 수 있도록 설계된 React Hook이다.
const [state, action, isPending] =useActionState(
actionFn,
initialState
)
핵심은 “이 폼은 이 액션과 이 상태를 가진다” 라는 관계를 선언적으로 표현할 수 있다는 점이다.
예시
기존 방식 (useState + onSubmit)
const [loading, setLoading] =useState(false);
const [result, setResult] =useState(null);
constonSubmit =async (e) => {
e.preventDefault();
setLoading(true);
const res =awaitfetch("/api/login", {method:"POST" });
const data =await res.json();
setResult(data);
setLoading(false);
};
- 상태 변경 타이밍을 직접 관리해야 함
- 요청 흐름이 늘어날수록 가독성 급격히 하락
useActionState 적용
constloginAction =async (prevState, formData) => {
const res =awaitfetch("/api/login", {
method:"POST",
body: formData,
});
returnawait res.json();
};
const [state, formAction, isPending] =
useActionState(loginAction,null);
return (
<formaction={formAction}>
<inputname="email" />
<inputname="password"type="password" />
<buttondisabled={isPending}>
{isPending ? "로그인 중..." : "로그인"}
</button>
{state &&<p>{state.message}</p>}
</form>
);
✔️ 로딩 상태 자동 관리
✔️ 응답 데이터는 state로 일관되게 접근
✔️ onSubmit 자체가 필요 없음
Next.js에서의 강점 (Server Actions)
Next.js App Router에서는 액션 함수를 서버에서 바로 실행할 수 있다.
"use server";
exportasyncfunctionloginAction(prevState, formData) {
// DB 접근, 인증 로직
return {success:true };
}
const [state, action, pending] =
useActionState(loginAction,null);
<formaction={action}>
- API Route 불필요
- 클라이언트 → 서버 직행
- 네트워크 비용 감소 + 보안 강화
👉 폼 제출 = 서버 함수 호출이라는 직관적인 모델이 완성된다.
장점과 단점
장점
- ✅ 폼 관련 상태 로직 대폭 감소
- ✅ 비동기 요청 흐름이 선언적으로 표현됨
- ✅ Server Actions와 궁합이 매우 좋음
- ✅ 테스트 및 리팩터링 용이
단점
- ❌ React 19 이상에서만 사용 가능
- ❌ 기존
onSubmit패턴에 익숙한 경우 러닝커브 존재 - ❌ 복잡한 클라이언트 전처리가 필요한 폼에는 부적합할 수 있음
자주 하는 실수 & 좋은 팁
❌ 실수 1. useState와 함께 중복 사용
const [loading, setLoading] =useState(false);// ❌ 불필요
→ isPending가 이미 로딩 상태를 제공한다.
❌ 실수 2. form 없이 사용하려는 경우
useActionState는 form action 기반으로 설계되었다.
버튼 클릭 이벤트에 억지로 연결하면 장점이 사라진다.
✅ 좋은 팁 1. 초기 state를 명확하게 설계
const initialState = {
error:null,
success:false,
};
→ UI 분기 처리가 깔끔해진다.
✅ 좋은 팁 2. 서버 액션에서 검증 로직까지 처리
- 클라이언트 검증 + 서버 검증 이중화 가능
- 보안과 UX를 동시에 확보
면접 질문 예시
Q1. useActionState는 어떤 문제를 해결하기 위해 등장했나요?
모범 답변
기존 React 폼에서는 비동기 요청 시 loading, error, result 상태를 각각 관리해야 했고,
onSubmit 내부에서 상태 변경 순서를 직접 제어해야 했습니다.
useActionState는 이러한 폼 중심 비동기 상태 관리 문제를 선언적으로 해결하기 위해 도입되었습니다.
Q2. useActionState와 useTransition의 차이는 무엇인가요?
모범 답변
useTransition은 UI 우선순위 제어를 위한 Hook이고,
useActionState는 폼 액션의 실행과 그 결과 상태를 관리하는 Hook입니다.
목적과 책임이 다르며, useActionState는 폼 제출이라는 명확한 컨텍스트에 특화되어 있습니다.
Q3. (꼬리 질문) Next.js에서 useActionState를 쓰는 이유는 무엇인가요?
모범 답변
Next.js Server Actions와 결합하면 API Route 없이 서버 함수를 직접 호출할 수 있어
네트워크 비용이 줄고 보안이 강화됩니다.
또한 클라이언트 코드가 단순해져 유지보수성이 크게 향상됩니다.
Q4. (꼬리 질문) 모든 폼에 useActionState를 적용하는 것이 좋을까요?
모범 답변
단순 제출형 폼이나 서버 중심 로직에는 매우 적합하지만,
복잡한 클라이언트 인터랙션이나 실시간 validation 중심 폼에는
기존 상태 관리 방식이 더 적합할 수 있습니다.
상황에 맞는 선택이 중요합니다.
useActionState는 단순한 Hook 추가가 아니라,
React가 폼과 서버를 바라보는 관점 자체를 바꾸는 시도에 가깝다.
App Router 환경에서 폼을 다룬다면, 더 이상 선택이 아니라 기본기가 되는 도구다.