<input>

Вбудований компонент браузера <input> компонента дозволяє відображати різні типи введень у формі.

<input />

Довідник

<input>

Щоб відобразити вхідні дані, відрендерити вбудований у браузер компонент <input>.

<input name="myInput" />

Дивіться більше прикладів нижче.

Пропси

<input> підтримує всі пропси спільних елементів.

Розширення React для пропсу formAction наразі доступні лише в Canary та експериментальних каналах React. У стабільних випусках React formAction працює лише як вбудований HTML-компонент браузера. Дізнайтеся більше про канали випуску React тут.

formAction: Рядок або функція. Перевизначає батьківський <form action> для type="submit" і type="image". При передачі URL до action форма поводитиметься як стандартна HTML-форма. Коли функція передається в formAction, вона буде обробляти відправку форми. Дивіться <form action>.

Ви можете зробити вхід контрольованим шляхом передачі одного з цих пропсів:

  • checked: Логічний вираз. Для прапорця або перемикача, контролює, чи він вибраний.
  • value: Рядок. Для текстового введення керує його текстом. (Для перемикача - визначає дані його форми)
  • .

Коли ви передаєте будь-який з них, ви також повинні передати обробник onChange, який оновлює передане значення.

Ці пропси <input> актуальні лише для неконтрольованих входів:

Ці <input> пропси актуальні як для неконтрольованих, так і для контрольованих входів:

  • accept: Рядок. Вказує, які типи файлів приймаються вхідними даними type="file".
  • alt: Рядок. Вказує альтернативний текст зображення для вхідних даних type="image".
  • capture: Рядок. Вказує носій (мікрофон, відео або камеру), захоплений входом type="file".
  • autoComplete: Рядок. Вказує одну з можливих поведінок автозаповнення.
  • autoFocus: Логічний вираз. Якщо true, React сфокусує елемент на монтуванні.
  • dirname: Рядок. Вказує ім'я поля форми для напрямку елемента.
  • disabled: Логічний вираз. Якщо true, введення не буде інтерактивним і буде виглядати затемненим.
  • children: <input> не приймає дітей.
  • form: Рядок. Вказує ідентифікатор id елемента <form>, до якого належить цей вхід. Якщо не вказано, це найближча батьківська форма.
  • formAction: Рядок. Перевизначає батьківський <form action> для type="submit" та type="image".
  • formEnctype: Рядок. Перевизначає батьківський <form enctype> для type="submit" та type="image".
  • formMethod: Рядок. Перевизначає батьківський <form method> для type="submit" та type="image".
  • formNoValidate: Рядок. Перевизначає батьківський <form noValidate> для type="submit" та type="image".
  • formTarget: Рядок. Перевизначає батьківський <form target> для type="submit" та type="image".
  • height: Рядок. Вказує висоту зображення для type="image".
  • .
  • list: Рядок. Вказує id з <datalist> з опціями автозаповнення.
  • max: Число. Вказує максимальне значення числових входів та входів часу даних.
  • maxLength: Число. Визначає максимальну довжину тексту та інших вхідних даних.
  • .
  • min: Число. Вказує мінімальне значення числових входів та входів часу даних.
  • minLength: Число. Визначає мінімальну довжину тексту та інших вхідних даних.
  • multiple: Булеве значення. Визначає, чи дозволено множинні значення для <type="file" та type="email".
  • name: Рядок. Вказує назву для цього входу, який було надіслано разом з формою.
  • onChange: Функція-обробник Event . Потрібна для контрольованих входів. Спрацьовує негайно, коли значення входу змінюється користувачем (наприклад, спрацьовує на кожне натискання клавіші). Поводиться як браузер input event.
  • onChangeCapture: Версія onChange, яка спрацьовує у фазі захоплення.
  • onInput: Функція-обробник Event . Спрацьовує негайно, коли користувач змінює значення. З історичних причин у React ідіоматичним є використання onChange, який працює аналогічно.
  • onInputCapture: Версія onInput, яка спрацьовує у фазі захоплення.
  • onInvalid: Функція-обробник Event . Спрацьовує, якщо вхідні дані не пройшли валідацію при надсиланні форми. На відміну від вбудованої події invalid, подія React onInvalid bubbles.
  • onInvalidCapture: Версія onInvalid, яка спрацьовує у фазі захоплення.
  • onSelect: Функція-обробник Event . Спрацьовує після зміни виділення всередині <input>. React розширює подію onSelect, щоб вона спрацьовувала також для порожнього виділення та при редагуванні (яке може вплинути на виділення).
  • onSelectCapture: Версія onSelect, яка спрацьовує у фазі захоплення.
  • pattern: Рядок. Вказує шаблон, якому має відповідати значення.
  • placeholder: Рядок. Відображається тьмяним кольором, якщо вхідне значення порожнє.
  • readOnly: Логічний вираз. Якщо true, вхідні дані не можна редагувати користувачу.
  • required: Булеве значення. Якщо true, значення має бути надано формі для відправки.
  • size: Число. Подібно до налаштування ширини, але одиниця виміру залежить від елемента керування.
  • src: Рядок. Вказує джерело зображення для входу type="image".
  • .
  • step: Додатне число або рядок 'any'. Визначає відстань між допустимими значеннями.
  • type: Рядок. Один з типів входу.
  • width: Рядок. Вказує ширину зображення для вхідних даних type="image".

Застереження

  • Прапорці потрібно встановити (або defaultChecked), а не value (або defaultValue).
  • Якщо текстове введення отримує рядковий проп зі значенням , він буде оброблений як контрольований.
  • Якщо прапорець або перемикач отримує відмічений булевий проп , він буде вважатися керованим.
  • Вхід не може бути одночасно контрольованим та неконтрольованим.
  • Вхід не може перемикатися між контрольованим та неконтрольованим протягом свого життя.
  • Кожному керованому входу потрібен обробник події 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>
    </>
  );
}
label { display: block; }
input { margin: 5px; }

Надання мітки для входу

Зазвичай ви розміщуєте кожну <input> всередині тегу <label>. Це повідомляє браузеру, що ця мітка пов'язана з цим входом. Коли користувач клацне на мітці, браузер автоматично сфокусує введення. Це також важливо для доступності: програма для зчитування з екрана озвучить підпис мітки, коли користувач сфокусує відповідне введення.

Якщо ви не можете вкласти <input> у <label>, об'єднайте їх, передавши однаковий ідентифікатор <input id> та <label htmlFor>. Щоб уникнути конфліктів між екземплярами одного компонента, згенеруйте такий ідентифікатор за допомогою useId.

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" />
    </>
  );
}
input { margin: 5px; }

Надання початкового значення для входу

За бажанням ви можете вказати початкове значення для будь-якого входу. Для текстових введень передайте його у вигляді рядка 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>
    </>
  );
}
label { display: block; }
input { margin: 5px; }

Зчитування вхідних значень під час надсилання форми

Додайте <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>
  );
}
label { display: block; }
input { margin: 5px; }

Дайте ім'я кожному <input>, наприклад <input name="firstName" defaultValue="Taylor" />. Вказане вами name буде використано як ключ у даних форми, наприклад { firstName: "Taylor" }.

За замовчуванням, будь-який <button> всередині <form> надішле його. Це може бути несподівано! Якщо у вас є власний кастомний Button React-компонент, розгляньте можливість повернення <button type="button"> замість <button>. Тоді, для більшої ясності, використовуйте <button type="submit"> для кнопок, які мають надсилати форму.


Керування входом за допомогою змінної стану

Введення типу <input /> є неконтрольованим. Навіть якщо ви передаєте початкове значення типу <input defaultValue="Initial text" />, ваш JSX лише вказує початкове значення. Він не контролює, яким має бути значення зараз.

Щоб відрендерити контрольоване введення, передайте йому проп value (або перемикач для чекбоксів та радіо). React змусить вхідні дані завжди мати значення , яке ви передали. Зазвичай ви робите це, оголошуючи змінну стану :

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!
    />
  );
}

Контрольоване введення має сенс, якщо вам все одно потрібен стан - наприклад, для повторного рендерингу інтерфейсу після кожного редагування:

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>

Значення , яке ви передаєте керованим компонентам, не повинно бути невизначеним або нульовим. Якщо вам потрібно, щоб початкове значення було порожнім (як у випадку з полем 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>
      }
    </>
  );
}
label { display: block; }
input { margin: 5px; }
p { font-weight: bold; }

Якщо ви передасте значення без onChange, ввід буде неможливим. Коли ви керуєте входом, передаючи йому деяке значення, ви примушуєте його завжди мати значення, яке ви передали. Отже, якщо ви передасте змінну стану як значення, але забудете синхронно оновити цю змінну стану під час обробника події onChange, React повертатиме вхідні дані після кожного натискання клавіші до значення, яке ви вказали.


Оптимізація повторного рендерингу на кожне натискання клавіші

Коли ви використовуєте контрольоване введення, ви встановлюєте стан на кожне натискання клавіші. Якщо компонент, який містить ваш стан, повторно рендерить велике дерево, це може бути повільним. Існує декілька способів оптимізувати продуктивність повторного рендерингу.

Наприклад, припустимо, що ви почнете з форми, яка повторно відображає весь вміст сторінки після кожного натискання клавіші:

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 дозволяє зберегти керовані введення чуйним навіть під час великого повторного рендерингу.


Налагодження

Моє вікно введення тексту не оновлюється, коли я вводжу в нього текст

Якщо ви відрендерите введення зі значенням , але без onChange, ви побачите помилку у консолі:

// 🔴 Bug: controlled text input with no onChange handler
<input value={something} />

Ви надали проп значення полю форми без обробника 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} />

Мій прапорець не оновлюється, коли я натискаю на нього

Якщо ви відрендерите чекбокс з встановленим прапорцем , але без onChange, ви побачите помилку в консолі:

// 🔴 Bug: controlled checkbox with no onChange handler
<input type="checkbox" checked={something} />

Ви додали перевірений проп до поля форми без обробника 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)} />

Для прапорців потрібно читати e.target.checked, а не e.target.value.

Якщо прапорець навмисно зроблено лише для читання, додайте проп readOnly, щоб приховати помилку:

// ✅ Good: readonly controlled input without on change
<input type="checkbox" checked={something} readOnly={true} />

При кожному натисканні клавіші курсор введення перескакує на початок

Якщо ви керуєте входом, ви повинні оновити його змінну стану до значення входу з DOM під час onChange.

Ви не можете оновити його на щось інше, ніж 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. Це може статися, якщо ви випадково скидаєте стан при кожному повторному рендерингу, наприклад, якщо вхід або один з його батьків завжди отримує інший атрибут ключа, або якщо ви вкладаєте визначення функцій компонентів (що не підтримується і призводить до того, що "внутрішній" компонент завжди буде вважатися іншим деревом).


Я отримую помилку: "Компонент змінює неконтрольований вхід на контрольований"

Якщо ви надаєте компоненту значення, воно має залишатися рядком протягом усього його життя.

Ви не можете передати спочатку value={undefined}, а потім value="some string", оскільки React не знатиме, чи хочете ви зробити компонент некерованим чи керованим. Керований компонент завжди повинен отримувати рядок value, а не null або undefined.

Якщо ваше значення надходить з API або змінної стану, воно може бути ініціалізоване null або undefined. У такому випадку або спочатку встановіть його як порожній рядок (''), або передайте value={someValue ?? ''}, щоб переконатися, що value є рядком.

Так само, якщо ви передаєте checked до прапорця, переконайтеся, що він завжди є логічним.