內建瀏覽器 <input> 元件 可讓您渲染不同種類的表單輸入。
<input />參考
<input>
要顯示輸入,請渲染內建瀏覽器 <input> 元件。
<input name="myInput" />屬性
<input> 支援所有 常用元件屬性。
formAction:一個字串或函式。覆蓋父元件 <form action> 中type="submit"和type="image"的設定。當 URL 傳遞給action時,表單的行為將像標準 HTML 表單一樣。當函式傳遞給formAction時,該函式將處理表單提交。請參閱<form action>。
您可以通過傳遞以下其中一個屬性來 使輸入受控
checked:一個布林值。對於核取方塊輸入或單選按鈕,控制它是否被選中。value:一個字串。對於文字輸入,控制其文字。(對於單選按鈕,指定其表單數據。)
當您傳遞其中任何一個時,您也必須傳遞一個 onChange 事件處理器,用於更新傳遞的值。
這些 <input> 屬性僅與非受控輸入相關。
defaultChecked:一個布林值。指定type="checkbox"和type="radio"輸入的初始值。defaultValue:一個字串。指定文字輸入的初始值。
這些 <input> 屬性與非受控和受控輸入皆相關。
accept:一個字串。指定type="file"輸入所接受的檔案類型。alt:一個字串。指定type="image"輸入的替代圖片文字。capture:一個字串。指定type="file"輸入所擷取的媒體(麥克風、影片或相機)。autoComplete:一個字串。指定其中一種可能的自動完成行為。autoFocus:一個布林值。如果為true,React 將在掛載時聚焦此元素。dirname:一個字串。指定元素方向性的表單欄位名稱。disabled:一個布林值。如果為true,則輸入將無法互動,並顯示為灰色。children:<input>不接受子元素。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"輸入的圖片寬度。
注意事項
- 核取方塊需要使用
checked(或defaultChecked)屬性,而不是value(或defaultValue)屬性。 - 如果文字輸入框收到一個字串类型的
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> 來關聯它們。為了避免一個組件的多個實例之間發生衝突,請使用 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" /> </> ); }
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> </> ); }
提交表單時讀取輸入值
在您的輸入周圍加上一個帶有 <button type="submit"> 的 <form>。它會呼叫您的 <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} />value 屬性給表單欄位,但沒有 onChange 處理程式。這將會渲染一個唯讀欄位。如果該欄位應該是可變的,請使用 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} />checked 屬性給表單欄位,但沒有 onChange 處理程式。這將會渲染一個唯讀欄位。如果該欄位應該是可變的,請使用 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 無法知道您是要將元件設為非受控還是受控。受控元件應始終接收字串`value`,而不是`null`或`undefined`。
如果您的`value`來自 API 或狀態變數,它可能會初始化為`null`或`undefined`。在這種情況下,請先將其設定為空字串(`''`),或傳遞`value={someValue ?? ''} `以確保`value`是字串。
同樣地,如果您將`checked`傳遞給核取方塊,請確保它始終是布林值。