フォーム管理
React
制御・非制御コンポーネント・バリデーション
制御コンポーネント
Reactが入力値を管理するパターン
import { useState, type FormEvent, type ChangeEvent } from 'react';
interface FormData {
name: string;
email: string;
password: string;
role: 'user' | 'admin';
agree: boolean;
}
function SignupForm() {
const [form, setForm] = useState<FormData>({
name: '', email: '', password: '', role: 'user', agree: false
});
const [errors, setErrors] = useState<Partial<FormData>>({});
// 汎用ハンドラー
const handleChange = (e: ChangeEvent<HTMLInputElement | HTMLSelectElement>) => {
const { name, value, type } = e.target;
setForm(prev => ({
...prev,
[name]: type === 'checkbox' ? (e.target as HTMLInputElement).checked : value,
}));
};
const handleSubmit = (e: FormEvent) => {
e.preventDefault();
const errs: Partial<FormData> = {};
if (!form.name) errs.name = '名前は必須です';
if (!form.email) errs.email = 'メールは必須です';
if (Object.keys(errs).length) { setErrors(errs); return; }
// submit処理...
};
return (
<form onSubmit={handleSubmit}>
<input name="name" value={form.name} onChange={handleChange} />
{errors.name && <p className="text-red-500">{errors.name}</p>}
<input name="email" value={form.email} onChange={handleChange} type="email" />
<input name="agree" checked={form.agree} onChange={handleChange} type="checkbox" />
<button type="submit">登録</button>
</form>
);
}非制御コンポーネント / useFormStatus
ref・FormData・Server Actions
import { useRef } from 'react';
// 非制御コンポーネント(シンプルなフォームに)
function SimpleForm() {
const nameRef = useRef<HTMLInputElement>(null);
const emailRef = useRef<HTMLInputElement>(null);
const handleSubmit = (e: FormEvent) => {
e.preventDefault();
const name = nameRef.current?.value;
const email = emailRef.current?.value;
// 処理...
};
return (
<form onSubmit={handleSubmit}>
<input ref={nameRef} defaultValue="" />
<input ref={emailRef} defaultValue="" type="email" />
<button type="submit">送信</button>
</form>
);
}
// FormData API(ネイティブフォームデータ取得)
function NativeForm() {
const handleSubmit = (e: FormEvent<HTMLFormElement>) => {
e.preventDefault();
const data = new FormData(e.currentTarget);
const name = data.get('name') as string;
const email = data.get('email') as string;
// 処理...
};
return (
<form onSubmit={handleSubmit}>
<input name="name" />
<input name="email" type="email" />
<button type="submit">送信</button>
</form>
);
}