內建瀏覽器 <input> 元件 可讓您渲染不同種類的表單輸入。

<input />

參考

<input>

要顯示輸入,請渲染內建瀏覽器 <input> 元件

<input name="myInput" />

請參閱下面的更多範例。

屬性

<input> 支援所有 常用元件屬性

  • formAction:一個字串或函式。覆蓋父元件 <form action>type="submit"type="image" 的設定。當 URL 傳遞給 action 時,表單的行為將像標準 HTML 表單一樣。當函式傳遞給 formAction 時,該函式將處理表單提交。請參閱 <form action>

您可以通過傳遞以下其中一個屬性來 使輸入受控

當您傳遞其中任何一個時,您也必須傳遞一個 onChange 事件處理器,用於更新傳遞的值。

這些 <input> 屬性僅與非受控輸入相關。

這些 <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" />
    </>
  );
}


提供輸入的初始值

您可以選擇性地指定任何輸入的初始值。將其作為 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>
    </>
  );
}


提交表單時讀取輸入值

在您的輸入周圍加上一個帶有 <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> 指定一個 name,例如 <input name="firstName" defaultValue="Taylor" />。您指定的 name 將在表單資料中用作鍵,例如 { firstName: "Taylor" }

陷阱

預設情況下,<form> 內的*任何* <button> 都會提交它。這可能會令人感到意外!如果您有自己的客製化 Button React 組件,請考慮回傳 <button type="button"> 而不是 <button>。然後,為了明確起見,請使用 <button type="submit"> 來表示*應該*提交表單的按鈕。


使用狀態變數控制輸入

<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 不應該是 undefinednull。如果您需要初始值為空(例如底下的 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>
      }
    </>
  );
}

陷阱

如果您傳遞 value 而不傳遞 onChange,則無法在輸入中輸入。 當您透過傳遞一些 value 來控制輸入時,您*強制*它始終具有您傳遞的值。因此,如果您傳遞一個狀態變數作為 value,但忘記在 onChange 事件處理程式中同步更新該狀態變數,React 會在每次按鍵後將輸入還原為您指定的 value


在每次按鍵時優化重新渲染

當您使用受控輸入時,您會在每次按鍵時設定狀態。如果包含您狀態的組件重新渲染一個大型樹狀結構,這可能會變慢。您可以透過幾種方式來優化重新渲染效能。

例如,假設您一開始有一個表單,每次按鍵都會重新渲染所有頁面內容

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。否則,請設定 onChangereadOnly

如同錯誤訊息所示,如果您只想指定*初始*值,請改傳遞 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。否則,請設定 onChangereadOnly

如同錯誤訊息所示,如果您只想指定*初始*值,請改傳遞 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)} />

陷阱

您需要讀取核取方塊的 e.target.checked 而不是 e.target.value

如果核取方塊故意設為唯讀,請新增一個 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`傳遞給核取方塊,請確保它始終是布林值。