들어가며
폼을 다루다 보면 로딩 상태 관리가 늘 골치 아프죠?
버튼은 비활성화하고, 스피너는 보여주고... 이런 보일러플레이트 코드에 지치셨다면,
React 19의 `useFormStatus`가 여러분의 구원자가 될 거예요! 😊
useFormStatus란? 🤔
`useFormStatus`는 React의 Form Action과 함께 사용되는 훅으로, 폼의 제출 상태를 자동으로 추적합니다.
더 이상 로딩 상태를 수동으로 관리할 필요가 없어요!
기본 사용법 📝
```tsx
import { useFormStatus } from 'react-dom';
function SubmitButton() {
const { pending, data, method } = useFormStatus();
return (
<button
type="submit"
disabled={pending}
className={pending ? 'opacity-50' : ''}
>
{pending ? '제출 중...' : '제출하기'}
);
}
function SignupForm() {
async function handleSignup(formData: FormData) {
'use server';
// 서버 로직
}
return (
);
}
```
실전 활용 예시 💡
1. 로딩 상태에 따른 UI 변화
```tsx
function LoadingButton() {
const { pending } = useFormStatus();
return (
<button
type="submit"
className={`
flex items-center gap-2
${pending ? 'bg-gray-400' : 'bg-blue-500'}
text-white px-4 py-2 rounded
`}
disabled={pending}
>
{pending && (
)}
{pending ? '처리 중...' : '저장하기'}
);
}
```
2. 진행 상태 표시기
```tsx
function ProgressIndicator() {
const { pending } = useFormStatus();
return (
{pending && (
<div
className="absolute top-0 left-0 h-full bg-blue-500
animate-progress rounded-full"
style={{ width: '100%' }}
/>
)}
);
}
function UploadForm() {
async function handleUpload(formData: FormData) {
'use server';
// 파일 업로드 로직
}
return (
);
}
```
3. 폼 필드 비활성화 관리
```tsx
function SmartForm() {
const { pending } = useFormStatus();
return (
<fieldset disabled={pending} className={pending ? 'opacity-50' : ''}>
);
}
```
고급 활용 기법 🔥
1. 커스텀 훅으로 재사용
```tsx
function useFormStatusWithFeedback() {
const status = useFormStatus();
return {
...status,
buttonText: status.pending ? '처리 중...' : '제출하기',
buttonClass: `
btn ${status.pending ? 'btn-disabled' : 'btn-primary'}
`,
feedbackMessage: status.pending
? '요청을 처리하고 있습니다...'
: ''
};
}
function SmartButton() {
const { buttonText, buttonClass } = useFormStatusWithFeedback();
return (
);
}
```
2. 다중 폼 상태 관리
```tsx
function MultiStepForm() {
const [step, setStep] = useState(1);
const { pending } = useFormStatus();
return (
{step === 1 && (
<form action={async (formData) => {
await handleStep1(formData);
setStep(2);
}}>
<StepOneFields />
<NextStepButton />
</form>
)}
{step === 2 && (
<form action={handleStep2}>
<StepTwoFields />
<SubmitButton />
</form>
)}
</div>
);
}
```
3. 에러 처리와 결합
```tsx
function FormWithErrorHandling() {
const { pending } = useFormStatus();
const [error, setError] = useState<string | null>(null);
async function handleSubmit(formData: FormData) {
try {
await submitData(formData);
setError(null);
} catch (e) {
setError(e.message);
}
}
return (
);
}
```
실용적인 컴포넌트 패턴 ⚡️
1. 스마트 폼 컴포넌트
```tsx
function SmartForm({
children,
action,
successMessage
}: SmartFormProps) {
const [message, setMessage] = useState('');
const { pending } = useFormStatus();
return (
<form
action={async (formData) => {
await action(formData);
setMessage(successMessage);
}}
>
<div className={pending ? 'opacity-50' : ''}>
{children}
{message && !pending && (
<div className="success-message">
{message}
</div>
)}
{pending && (
<div className="absolute inset-0 bg-white/50 flex items-center justify-center">
<LoadingSpinner />
</div>
)}
</form>
</div>
);
}
```
2. 조건부 버튼 렌더링
```tsx
function ActionButton({
pendingText = '처리 중...',
children
}: ActionButtonProps) {
const { pending, data } = useFormStatus();
return (
<button
type="submit"
disabled={pending}
className={`
transition-all duration-200
${pending ? 'bg-gray-400' : 'bg-blue-500 hover:bg-blue-600'}
text-white px-4 py-2 rounded
`}
>
{pending ? (
{pendingText}
) : children}
);
}
```
주의사항과 팁 ⚠️
- **컴포넌트 위치**
```tsx
// 🚫 잘못된 사용
function Form() {
const { pending } = useFormStatus(); // 동작하지 않음!
return ;
}
// ✅ 올바른 사용
function Form() {
return (
);
}
```
- **서버 컴포넌트 주의**
```tsx
// useFormStatus는 클라이언트 컴포넌트에서만 사용 가능
'use client';
function SubmitButton() {
const { pending } = useFormStatus();
// ...
}
```
마치며
`useFormStatus`는 폼 처리의 복잡성을 크게 줄여주는 강력한 도구입니다.
특히 서버 액션과 함께 사용할 때 그 진가를 발휘하죠.
이제 더 이상 로딩 상태 관리로 고민하지 마세요!
React 19의 새로운 기능들이 우리의 개발 경험을 이렇게 개선해주는 걸 보면
정말 기대가 되지 않나요? 😊
즐거운 코딩 되세요! 🚀
'React.js' 카테고리의 다른 글
[React 19] useOptimistic으로 낙관적 UI 구현하기 - 좋아요 버튼 UX 개선하기 (0) | 2025.03.17 |
---|---|
[React 19] useActionState로 서버 상태 관리하기 (0) | 2025.03.17 |
[React 19] useTransition으로 더 부드러운 UI 구현하기 (0) | 2025.03.17 |
[React] 렌더링 최적화하기 - React.memo 현명하게 사용하기 (0) | 2025.03.17 |
[React] 웹 페이지 복귀, 이탈 탐지 (가시성) (0) | 2023.06.28 |