useFormを作る
入力欄の数だけ state が増える
出品フォームには商品名と価格があります。素直に書くと、こうなります。
const [title, setTitle] = useState("");
const [price, setPrice] = useState("");ここに説明文とカテゴリと画像 URL が足されると、state が5つ、ハンドラも5つです。しかも出品フォームと、あとで作るプロフィール編集フォームで、同じ形のコードがまた並びます。前のレッスンの重複と同じ話です。
値をまとめて1つの state にする
入力欄ごとに state を分けず、オブジェクト1つで持ちます。
const [values, setValues] = useState({ title: "", price: "" });書き換えるときは、入力欄の name を手がかりにします。
function handleChange(e: ChangeEvent<HTMLInputElement>) {
const { name, value } = e.target;
setValues((prev) => ({ ...prev, [name]: value }));
}[name] は「変数 name の中身をキーにする」という書き方です。name="title" の欄なら title が、name="price" の欄なら price が書き換わります。ハンドラは1つで、入力欄が何個あっても足りるわけです。
...prev を忘れると、打った欄以外が消えます。前の値を広げてから上書きする、この順番が要ります。
useForm として切り出す
この形は、どのフォームでも同じです。だから useItems と同じようにフックへ出します。
export function useForm(initial: FormValues) {
const [values, setValues] = useState(initial);
function handleChange(e: ChangeEvent<HTMLInputElement>) { ... }
function reset() {
setValues(initial);
}
return { values, handleChange, reset };
}返すのは値だけではありません。handleChange のような関数も一緒に返します。カスタムフックが返すのは「値と、それを扱う道具の一式」です。送信のあとに空へ戻す reset も、フォームなら必ず要るのでここに入れておきます。
演習
出品フォームの入力管理を useForm へ移します。