useFormを作る
入力欄の数だけ state が増える
出品フォームには商品名と価格があります。素直に書くと、こうなります。
TypeScript (JSX)
const [title, setTitle] = useState("");
const [price, setPrice] = useState("");ここに説明文とカテゴリと画像 URL が足されると、state が5つ、ハンドラも5つです。しかも出品フォームと、あとで作るプロフィール編集フォームで、同じ形のコードがまた並びます。前のレッスンの重複と同じ話です。
値をまとめて1つの state にする
入力欄ごとに state を分けず、オブジェクト1つで持ちます。
TypeScript (JSX)
const [profile, setProfile] = useState({ nickname: "", city: "" });書き換えるときは、入力欄の name を手がかりにします。
プロフィールの市区町村だけを、選択済みの値で更新する例です。nickname は前の値のまま残します。
TypeScript (JSX)
const selectedCity = "札幌";
setProfile((previous) => ({ ...previous, city: selectedCity }));入力イベントの e.target.name が欄の名前、e.target.value が入力した文字です。演習ではこの取り出しを用意してあります。1つのハンドラの中で name を if で判定し、対応する固定キーを更新します。
...previous を忘れると、打った欄以外が消えます。前の値を広げてから上書きする、この順番が要ります。
useForm として切り出す
state と入力ハンドラをフックにまとめる考え方は、別のフォームでも使えます。初期値はフックの引数で受け取ります。空欄に戻す関数も、プロフィールなら次のようにまとめられます。
TypeScript (JSX)
function clearProfile() {
setProfile({ nickname: "", city: "" });
}返すのは値だけではありません。handleChange のような関数も一緒に返します。カスタムフックが返すのは「値と、それを扱う道具の一式」です。送信のあとに空へ戻す reset も、フォームなら必ず要るのでここに入れておきます。
演習
出品フォームの useForm の中で、欄ごとの更新と初期値へのリセットを書きます。フォームの表示とフックの呼び出しは用意してあります。