組み込みのブラウザ <input> コンポーネントを使用すると、さまざまな種類のフォーム入力をレンダリングできます。
<input />リファレンス
<input>
入力を表示するには、組み込みのブラウザ <input> コンポーネントをレンダリングします。
<input name="myInput" />プロパティ
<input> は、共通の要素プロパティをすべてサポートします。
formAction:文字列または関数。type="submit"およびtype="image"の場合、親の<form action>をオーバーライドします。actionに URL が渡されると、フォームは標準の HTML フォームのように動作します。formActionに関数が渡されると、その関数がフォームの送信を処理します。<form action>を参照してください。
次のプロパティのいずれかを渡すことで、入力を制御できます
checked:ブール値。チェックボックス入力またはラジオボタンの場合、選択されているかどうかを制御します。value:文字列。テキスト入力の場合、そのテキストを制御します(ラジオボタンの場合、フォームデータを指定します)。
いずれかを渡す場合は、渡された値を更新するonChangeハンドラーも渡す必要があります。
これらの<input>のpropsは、非制御の入力に対してのみ関連します。
defaultChecked: ブール値。初期値をtype="checkbox"とtype="radio"の入力に対して指定します。defaultValue: 文字列。初期値をテキスト入力に対して指定します。
これらの<input>のpropsは、非制御および制御の入力の両方に関連します。
accept: 文字列。type="file"入力で許可されるファイルタイプを指定します。alt: 文字列。type="image"入力の代替画像テキストを指定します。capture: 文字列。type="file"入力でキャプチャされるメディア(マイク、ビデオ、またはカメラ)を指定します。autoComplete: 文字列。利用可能なオートコンプリートの動作のいずれかを指定します。autoFocus: ブール値。trueの場合、Reactはマウント時に要素にフォーカスを当てます。dirname: 文字列。要素の方向性のフォームフィールド名を指定します。disabled: ブール値。trueの場合、入力はインタラクティブではなくなり、薄暗く表示されます。children:<input>はchildrenを受け入れません。form: 文字列。この入力が属する<form>のidを指定します。省略した場合、最も近い親フォームになります。formAction: 文字列。type="submit"とtype="image"の場合、親の<form action>を上書きします。formEnctype: 文字列。type="submit"とtype="image"の場合、親の<form enctype>を上書きします。formMethod: 文字列。type="submit"とtype="image"の場合、親の<form method>を上書きします。formNoValidate: 文字列。type="submit"とtype="image"の場合、親の<form noValidate>を上書きします。formTarget: 文字列。type="submit"とtype="image"の場合、親の<form target>を上書きします。height: 文字列。type="image"の画像の高さを指定します。list: 文字列。オートコンプリートのオプションを含む<datalist>のidを指定します。max: 数値。数値入力および日時入力の最大値を指定します。maxLength: 数値。テキスト入力およびその他の入力の最大長を指定します。min: 数値。数値入力および日時入力の最小値を指定します。minLength: 数値。テキスト入力およびその他の入力の最小長を指定します。multiple: 真偽値です。<type="file"およびtype="email"で複数の値を許可するかどうかを指定します。name: 文字列です。この入力項目の名前を指定します。この名前は、フォーム送信時に一緒に送信されます。onChange:Eventハンドラー関数です。制御された入力に必須です。ユーザーによって入力値が変更されたときに即座に発火します(例:すべてのキーストロークで発火)。ブラウザのinputイベントのように動作します。onChangeCapture:onChangeのキャプチャフェーズで発火するバージョンです。キャプチャフェーズで発火します。onInput:Eventハンドラー関数です。ユーザーによって値が変更されたときに即座に発火します。歴史的な理由から、Reactでは同様に動作するonChangeを使用するのが慣例となっています。onInputCapture:onInputのキャプチャフェーズで発火するバージョンです。キャプチャフェーズで発火します。onInvalid:Eventハンドラー関数です。フォーム送信時に、入力がバリデーションに失敗した場合に発火します。組み込みのinvalidイベントとは異なり、ReactのonInvalidイベントはバブリングします。onInvalidCapture:onInvalidのキャプチャフェーズで発火するバージョンです。キャプチャフェーズで発火します。onSelect:Eventハンドラー関数です。<input>内の選択範囲が変更された後に発火します。Reactは、onSelectイベントを拡張し、空の選択範囲や編集時(選択範囲に影響を与える可能性がある)にも発火するようにしています。onSelectCapture:onSelectのキャプチャフェーズで発火するバージョンです。キャプチャフェーズで発火します。pattern: 文字列です。valueが一致する必要があるパターンを指定します。placeholder: 文字列です。入力値が空の場合に、薄い色で表示されます。readOnly: 真偽値です。trueの場合、ユーザーによる入力の編集はできません。required: 真偽値です。trueの場合、フォームを送信するには値が必須です。size: 数値です。幅の設定と似ていますが、単位はコントロールによって異なります。src: 文字列です。type="image"の入力要素の画像ソースを指定します。step: 正の数値または'any'文字列です。有効な値の間の距離を指定します。type: 文字列です。入力タイプのいずれかです。width: 文字列です。type="image"の入力要素の画像の幅を指定します。
注意点
- チェックボックスは、
value(またはdefaultValue)ではなく、checked(またはdefaultChecked)が必要です。 - テキスト入力が文字列の
valueプロップを受け取ると、制御されたものとして扱われます。 - チェックボックスまたはラジオボタンがブール値の
checkedプロップを受け取ると、制御されたものとして扱われます。 - 入力は、制御されている状態と制御されていない状態を同時に持つことはできません。
- 入力は、そのライフサイクル中に制御された状態と制御されていない状態を切り替えることはできません。
- すべての制御された入力には、そのバックアップ値を同期的に更新する
onChangeイベントハンドラーが必要です。
使い方
異なる種類の入力を表示する
入力を表示するには、<input>コンポーネントをレンダリングします。デフォルトでは、テキスト入力になります。チェックボックスの場合はtype="checkbox"を、ラジオボタンの場合はtype="radio"を、またはその他の入力タイプを渡すことができます。
export default function MyForm() { return ( <> <label> Text input: <input name="myInput" /> </label> <hr /> <label> Checkbox: <input type="checkbox" name="myCheckbox" /> </label> <hr /> <p> Radio buttons: <label> <input type="radio" name="myRadio" value="option1" /> Option 1 </label> <label> <input type="radio" name="myRadio" value="option2" /> Option 2 </label> <label> <input type="radio" name="myRadio" value="option3" /> Option 3 </label> </p> </> ); }
入力にラベルを提供する
通常、すべての<input>を<label>タグの中に配置します。これにより、ブラウザはこのラベルがその入力に関連付けられていることを認識します。ユーザーがラベルをクリックすると、ブラウザは自動的に入力にフォーカスします。また、アクセシビリティにとっても重要です。スクリーンリーダーは、ユーザーが関連付けられた入力にフォーカスすると、ラベルのキャプションをアナウンスします。
<input>を<label>の中にネストできない場合は、同じIDを<input id>と<label htmlFor>に渡すことで関連付けます。1つのコンポーネントの複数のインスタンス間で競合を避けるために、useIdを使用してこのようなIDを生成します。
import { useId } from 'react'; export default function Form() { const ageInputId = useId(); return ( <> <label> Your first name: <input name="firstName" /> </label> <hr /> <label htmlFor={ageInputId}>Your age:</label> <input id={ageInputId} name="age" type="number" /> </> ); }
入力の初期値を設定する
オプションで、任意の入力の初期値を指定できます。テキスト入力の場合は、defaultValue文字列として渡します。チェックボックスとラジオボタンは、代わりにdefaultCheckedブール値で初期値を指定する必要があります。
export default function MyForm() { return ( <> <label> Text input: <input name="myInput" defaultValue="Some initial value" /> </label> <hr /> <label> Checkbox: <input type="checkbox" name="myCheckbox" defaultChecked={true} /> </label> <hr /> <p> Radio buttons: <label> <input type="radio" name="myRadio" value="option1" /> Option 1 </label> <label> <input type="radio" name="myRadio" value="option2" defaultChecked={true} /> Option 2 </label> <label> <input type="radio" name="myRadio" value="option3" /> Option 3 </label> </p> </> ); }
フォーム送信時に入力値を読み取る
<form>を、中に<button type="submit">を入れて、入力の周りに追加します。これにより、<form onSubmit>イベントハンドラーが呼び出されます。デフォルトでは、ブラウザはフォームデータを現在のURLに送信し、ページをリフレッシュします。その動作をオーバーライドするには、e.preventDefault()を呼び出します。new FormData(e.target)を使用してフォームデータを読み取ります。
export default function MyForm() { function handleSubmit(e) { // Prevent the browser from reloading the page e.preventDefault(); // Read the form data const form = e.target; const formData = new FormData(form); // You can pass formData as a fetch body directly: fetch('/some-api', { method: form.method, body: formData }); // Or you can work with it as a plain object: const formJson = Object.fromEntries(formData.entries()); console.log(formJson); } return ( <form method="post" onSubmit={handleSubmit}> <label> Text input: <input name="myInput" defaultValue="Some initial value" /> </label> <hr /> <label> Checkbox: <input type="checkbox" name="myCheckbox" defaultChecked={true} /> </label> <hr /> <p> Radio buttons: <label><input type="radio" name="myRadio" value="option1" /> Option 1</label> <label><input type="radio" name="myRadio" value="option2" defaultChecked={true} /> Option 2</label> <label><input type="radio" name="myRadio" value="option3" /> Option 3</label> </p> <hr /> <button type="reset">Reset form</button> <button type="submit">Submit form</button> </form> ); }
ステート変数による入力の制御
<input />のような入力は、非制御です。初期値を渡す場合でも、<input defaultValue="初期テキスト" />のように、JSXは初期値を指定するだけです。現在値を制御するわけではありません。
制御された入力をレンダリングするには、valueプロパティを(チェックボックスやラジオボタンの場合はcheckedを)渡してください。Reactは、入力が常に渡されたvalueを持つように強制します。通常、ステート変数を宣言することでこれを行います。
function Form() {
const [firstName, setFirstName] = useState(''); // Declare a state variable...
// ...
return (
<input
value={firstName} // ...force the input's value to match the state variable...
onChange={e => setFirstName(e.target.value)} // ... and update the state variable on any edits!
/>
);
}制御された入力は、例えば、編集ごとにUIを再レンダリングするためにステートが必要な場合に役立ちます。
function Form() {
const [firstName, setFirstName] = useState('');
return (
<>
<label>
First name:
<input value={firstName} onChange={e => setFirstName(e.target.value)} />
</label>
{firstName !== '' && <p>Your name is {firstName}.</p>}
...また、入力の状態を調整する複数の方法を提供したい場合にも便利です(例えば、ボタンをクリックするなど)。
function Form() {
// ...
const [age, setAge] = useState('');
const ageAsNumber = Number(age);
return (
<>
<label>
Age:
<input
value={age}
onChange={e => setAge(e.target.value)}
type="number"
/>
<button onClick={() => setAge(ageAsNumber + 10)}>
Add 10 years
</button>制御されたコンポーネントに渡すvalueは、undefinedやnullであってはいけません。初期値を空にしたい場合(以下のfirstNameフィールドなど)、ステート変数を空の文字列('')で初期化してください。
import { useState } from 'react'; export default function Form() { const [firstName, setFirstName] = useState(''); const [age, setAge] = useState('20'); const ageAsNumber = Number(age); return ( <> <label> First name: <input value={firstName} onChange={e => setFirstName(e.target.value)} /> </label> <label> Age: <input value={age} onChange={e => setAge(e.target.value)} type="number" /> <button onClick={() => setAge(ageAsNumber + 10)}> Add 10 years </button> </label> {firstName !== '' && <p>Your name is {firstName}.</p> } {ageAsNumber > 0 && <p>Your age is {ageAsNumber}.</p> } </> ); }
すべてのキーストロークでの再レンダリングの最適化
制御された入力を使用すると、すべてのキーストロークでステートを設定します。ステートを含むコンポーネントが大きなツリーを再レンダリングする場合、これが遅くなる可能性があります。再レンダリングのパフォーマンスを最適化する方法がいくつかあります。
例えば、すべてのキーストロークでページコンテンツ全体を再レンダリングするフォームから始めるとします。
function App() {
const [firstName, setFirstName] = useState('');
return (
<>
<form>
<input value={firstName} onChange={e => setFirstName(e.target.value)} />
</form>
<PageContent />
</>
);
}<PageContent />は入力ステートに依存しないため、入力ステートを独自のコンポーネントに移動できます。
function App() {
return (
<>
<SignupForm />
<PageContent />
</>
);
}
function SignupForm() {
const [firstName, setFirstName] = useState('');
return (
<form>
<input value={firstName} onChange={e => setFirstName(e.target.value)} />
</form>
);
}これにより、すべてのキーストロークでSignupFormのみが再レンダリングされるため、パフォーマンスが大幅に向上します。
再レンダリングを回避する方法がない場合(例えば、PageContentが検索入力の値に依存する場合)、useDeferredValueを使用すると、大規模な再レンダリング中でも制御された入力を応答性良く保つことができます。
トラブルシューティング
テキスト入力がタイプしても更新されない
valueがあり、onChangeがない入力をレンダリングすると、コンソールにエラーが表示されます。
// 🔴 Bug: controlled text input with no onChange handler
<input value={something} />onChangeハンドラーなしでフォームフィールドにvalueプロパティを渡しました。これにより、読み取り専用フィールドがレンダリングされます。フィールドが変更可能である必要がある場合は、defaultValueを使用してください。それ以外の場合は、onChangeまたはreadOnlyのいずれかを設定してください。エラーメッセージが示すように、初期値を指定したいだけの場合は、代わりにdefaultValueを渡してください。
// ✅ Good: uncontrolled input with an initial value
<input defaultValue={something} />この入力をステート変数で制御したい場合は、onChangeハンドラーを指定してください。
// ✅ Good: controlled input with onChange
<input value={something} onChange={e => setSomething(e.target.value)} />値が意図的に読み取り専用である場合は、エラーを抑制するためにreadOnlyプロパティを追加してください。
// ✅ Good: readonly controlled input without on change
<input value={something} readOnly={true} />チェックボックスをクリックしても更新されません。
checkedを指定してチェックボックスをレンダリングし、onChangeを指定しない場合、コンソールにエラーが表示されます。
// 🔴 Bug: controlled checkbox with no onChange handler
<input type="checkbox" checked={something} />onChangeハンドラーなしで、フォームフィールドにcheckedプロパティを指定しました。これにより、読み取り専用フィールドがレンダリングされます。フィールドが変更可能である必要がある場合は、defaultCheckedを使用してください。それ以外の場合は、onChangeまたはreadOnlyを設定してください。エラーメッセージが示唆するように、初期値を指定したいだけであれば、代わりにdefaultCheckedを渡してください。
// ✅ Good: uncontrolled checkbox with an initial value
<input type="checkbox" defaultChecked={something} />ステート変数を使用してこのチェックボックスを制御したい場合は、onChangeハンドラーを指定してください。
// ✅ Good: controlled checkbox with onChange
<input type="checkbox" checked={something} onChange={e => setSomething(e.target.checked)} />チェックボックスが意図的に読み取り専用である場合は、エラーを抑制するためにreadOnlyプロパティを追加してください。
// ✅ Good: readonly controlled input without on change
<input type="checkbox" checked={something} readOnly={true} />入力キャレットがキーストロークごとに先頭にジャンプします。
入力を制御する場合、onChange中にDOMからの入力値にステート変数を更新する必要があります。
e.target.value(またはチェックボックスの場合はe.target.checked)以外に更新することはできません。
function handleChange(e) {
// 🔴 Bug: updating an input to something other than e.target.value
setFirstName(e.target.value.toUpperCase());
}また、非同期的に更新することもできません。
function handleChange(e) {
// 🔴 Bug: updating an input asynchronously
setTimeout(() => {
setFirstName(e.target.value);
}, 100);
}コードを修正するには、e.target.valueに同期的に更新してください。
function handleChange(e) {
// ✅ Updating a controlled input to e.target.value synchronously
setFirstName(e.target.value);
}これで問題が解決しない場合は、キーストロークごとにDOMから入力が削除されて再度追加される可能性があります。たとえば、入力またはその親のいずれかが常に異なるkey属性を受け取っている場合、またはコンポーネント関数定義をネストしている場合(これはサポートされておらず、「内部」コンポーネントが常に異なるツリーと見なされる原因になります)など、再レンダリングごとに誤ってステートをリセットすると、これが発生する可能性があります。
「コンポーネントが制御されていない入力を制御された状態に変更しています」というエラーが発生しています。
コンポーネントにvalueを指定する場合は、そのライフサイクル全体を通して文字列のままである必要があります。
最初にvalue={undefined}を渡し、後でvalue="some string"を渡すことはできません。Reactはコンポーネントを制御しない状態にするか、制御された状態にするかを判断できないためです。制御されたコンポーネントは、nullやundefinedではなく、常に文字列valueを受け取る必要があります。
valueがAPIまたはステート変数から取得されている場合、最初はnullまたはundefinedに初期化される可能性があります。その場合は、最初に空の文字列('')に設定するか、value={someValue ?? ''}を渡して、valueが文字列であることを確認してください。
同様に、チェックボックスにcheckedを渡す場合は、常にブール値であることを確認してください。