內建瀏覽器 <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`傳遞給核取方塊,請確保它始終是布林值。