【React】 フォームの作成をして、typeに応じた値の管理をする
Reactでは、フォームを表示する際にデフォルトで選択しておいたり、値を簡単に変数に入れるといったことが可能です。チェックボックスやmultipleなセレクトといった、複数項目を管理するものも見ていきましょう。
目次
変数とフォームの値を同期する
まずはシンプルな1行テキストや数値の場合を見てみます。
input
に入れる値はvalue
属性に、ユーザが入力した値を格納するには、onChange
などを使用して更新します。
import { useState } from "react"; export default function MyForm() { const [name, setName] = useState("abc"); const handleChangeName = (e) => { setName(e.target.value); } const handleSubmit = (e) => { // ... } return ( <> <p>入力中の値: {name}</p> <form onSubmit={handleSubmit} method="get"> <input type="text" name="name" value={name} onChange={handleChangeName} /> </form> </> ) }
この例では、input
の値にはname
を、値の更新にはhandleChangeName
関数を使用しています。onChange
なので、入力値が更新される度にhandleChangeName
が呼ばれます。
要素のイベントで入力されている値を取得するには、e.target.value
のようにします。target
は普通のイベントにおいても、イベントが発生した要素のDOMを取得するものでした。
フォームの送信
送信時に値を取得する際も、通常のイベントと同じように処理します。
画面遷移を防止したい場合、e.preventDefault();
する必要があります。
const handleSubmit = (e) => { // 送信後の画面遷移を防止 e.preventDefault(); // form内の値であれば、name属性の値を指定して値を取得できる const name = e.target.name.value; // ... }
種類に応じた値
inputの種類によって、値の入り方が違います。それぞれを見ていきましょう。
text、number、他文字列系のもの
typeがtext
とnumber
では、普通の文字列を取り扱います。numberでも、取得する際は文字列です。
他にも、email
、tel
なども普通の文字列です。
const handleChangeName = (e) => { // textでもnumberでも普通の文字列 setName(e.target.value); }
<input type="text" value={name} onChange={handleChangeName} />
date
日付型の場合、yyyy-mm-dd
の形式を利用します。値自体は文字列です。
const [value, setValue] = useState("2022-04-01"); const handleChangeValue = (e) => { setName(e.target.value); }
<input type="date" value={value} onChange={handleChangeValue} />
textarea
textarea
でも、扱い方はinput
と同じです。もし文字列を改行したい場合は\n
を入れます。
const [text, setText] = useState("hoge\nfuga\nhige"); const handleChangeText = (e) => { setText(e.target.value); }
<textarea value={text} onChange={handleChangeText} cols="30" rows="10"></textarea>
ラジオボタン
ラジオボタンでは、一連の同じname
のうち1つを選択します。この時、チェックを入れたものを変更したときの挙動はonChange
を利用して他と同様に設定します。
チェックを入れたときの値はvalue
属性に入れ、最初からチェックが入っているかどうかの設定にはchecked
属性にbooleanで入れます。
// valueにはチェックが入っている項目のvalue属性の値が入る const [value, setValue] = useState("bar"); const handleChangeValue = (e) => { setValue(e.target.value); }
foo <input type="radio" name="radio1" value="foo" onChange={handleChangeValue} checked={value === "foo"} /> bar <input type="radio" name="radio1" value="bar" onChange={handleChangeValue} checked={value === "bar"} /> baz <input type="radio" name="radio1" value="baz" onChange={handleChangeValue} checked={value === "baz"} />
チェックボックス
チェックボックスでは、チェックが入っているかどうかの状態の管理は自前で実装する必要があります。キーにvalue
属性の値を、値にチェックが入っているかのbooleanを持たせて管理すると良いです。
もちろん、それ以外の実装でも大丈夫です。
const [values, setValues] = useState({}); const handleChangeValue = (e) => { setValues({ ...values, [e.target.value]: e.target.checked }); }
foo:<input type="checkbox" value="foo" onChange={handleChangeValue} checked={values["foo"] ?? false} /> bar:<input type="checkbox" value="bar" onChange={handleChangeValue} checked={values["bar"] ?? false} /> baz:<input type="checkbox" value="baz" onChange={handleChangeValue} checked={values["baz"] ?? false} />
checked={values["baz"] ?? false}
のようにしているのは、undefined
とfalse
の扱いが異なるためです。
undefined
の場合は、その属性を制御対象とはしないという扱いにします。これがtrue
に変わると、制御対象としていないはずのものが制御対象となるため、コードが間違っているのではないかと解釈され、警告が表示されます。
本当にそういった場合に気がつけるように、undefined
やnull
ではなくfalse
が入るようにしておく必要があります。
select
select
は複数項目から1つを選ぶものでした。select
タグ側のvalue
に、選択したいoptions
のvalue
属性の値を設定します。
const [value, setValue] = useState("bar"); const handleChangeValue = (e) => { setValue(e.target.value); }
<select value={value} onChange={handleChangeValue}> <option value="foo">foo</option> <option value="bar">bar</option> <option value="baz">baz</option> </select>
multiple
select
では、multiple
属性を付けると複数選択が可能になります。multiple
の場合、配列で管理します。
ここで、選択されている項目を取得してセットする操作は自前で実装する必要があります。
const [value, setValue] = useState(["bar", "baz"]); const handleChangeValue = (e) => { // HTMLCollectionでは操作が制限されるので、配列に変換 const selections = Array.prototype.slice.call(e.target.selectedOptions); // 選択されている項目の`value`を取得 setValue(selections.map(v => v.value)); }
<select value={value} onChange={handleChangeValue} multiple> <option value="foo">foo</option> <option value="bar">bar</option> <option value="baz">baz</option> </select>
file
file
は、Reactでは制御できない種類になります。できることといえば、DOMノードへの参照を作成することくらいです。
const [value, setValue] = useState(null); const handleChangeValue = (e) => { setValue(e.target); // ファイルパスが取得できる (セキュリティのため、道中のパスは自動で隠される) console.log(e.target.value); }
<input type="file" onChange={handleChangeValue} />
まとめ
各種inputの形式に応じた値の更新や格納方法はおおよそ似通っています。ラジオボタン、チェックボックス、ファイルの3つをどう扱えば良いかを把握すれば、殆どのフォームを作ることができるようになります。
