独自の入力部品の値を送る
リッチテキストエディタや独自の選択UIのように、<input name>を描かないコンポーネントの値は、そのままではFormDataに入りません。このページでは、こうした値をHiddenValueで送信に載せる方法を紹介します。
このページの内容
値を隠れた入力欄に置く
コンポーネントの値はstateに持ち、同じ値をHiddenValueに渡します。nameには、スキーマでのパスを書きます。
post-form.tsxconst [body, setBody] = useState(post.body);
<Editor onChange={setBody} value={body} />
<HiddenValue name="body" value={body} />HiddenValueはただの<input type="hidden">を描くので、値はほかの入力欄と一緒に送信されます。送信のときに値を集めるコードは要りません。
propsではなくコンポーネントになっている理由
Reactがvalueを書き換えても、DOMのイベントは起きません。そのため、ただの隠れた入力欄では、複数の入力欄にまたがるルールもisDirtyも、値が変わったことに気づけません。
HiddenValueは、値が変わるたびにinputイベントを出します。これで、キー入力と同じようにルールの判定とisDirtyが更新されます。
気をつけること
落とし穴
隠れた入力欄は、ブラウザの検証の対象になりません。requiredやminのような制約は、ブラウザでは確かめられず、送信されたあとにサーバーで初めて確かめます。
フォームをリセットしても、HiddenValueの値は戻りません。値は呼び出し側のstateにあるからです。リセットに合わせてstateも戻すなら、onResetでform.props.onReset()を呼んだあとに戻します。
post-form.tsx<form
{...form.props}
onReset={() => {
form.props.onReset();
setBody(post.body);
}}
>メモ
@k8ordo/uiのコンポーネントは、値を自分で送信に載せます。Autocompleteのように見た目と送信する要素が違うものも、HiddenValueは要りません。
星の評価を送る
星のボタンは<input>を持たない自前の入力部品です。選んだ値をHiddenValueで送信に載せています。
試してみる
- 星を選ぶと、
isDirtyがtrueに変わります。値の変化をHiddenValueがイベントで知らせているためです。 - 「送信」を押すと、送られる値が
rating=3のように表示されます。 - 「元に戻す」を押すと、星の選択も
isDirtyも元に戻ります。