Spec-Zone.ru › React 17

Формы

Элементы форм HTML работают немного иначе, чем другие элементы DOM в React, потому что элементы форм естественным образом сохраняют некоторое внутреннее состояние. Например, эта форма в обычном HTML принимает единственное имя:

<form>
  <label>
    Name:
    <input type="text" name="name" />
  </label>
  <input type="submit" value="Submit" />
</form>

Эта форма имеет стандартное поведение HTML-формы, переходящей на новую страницу при отправке формы. Если вам нужно это поведение в React, оно просто работает. Но в большинстве случаев удобно иметь функцию JavaScript, которая обрабатывает отправку формы и имеет доступ к данным, введенным пользователем в форму. Стандартный способ достижения этого — с помощью техники, называемой «управляемые компоненты».

Управляемые компоненты

В HTML такие элементы формы, как <input>, <textarea>, и <select> обычно поддерживают собственное состояние и обновляют его на основе пользовательского ввода. В React изменяемое состояние обычно хранится в свойстве состояния компонентов и обновляется только с помощью setState().

Мы можем объединить эти два подхода, сделав состояние React «единственным источником истины». Тогда компонент React, отображающий форму, также управляет тем, что происходит в этой форме при последующем пользовательском вводе. Элемент формы ввода, значение которого управляется React таким образом, называется «управляемым компонентом».

Например, если мы хотим, чтобы предыдущий пример выводил имя при отправке, мы можем записать форму как управляемый компонент:

class NameForm extends React.Component {
  constructor(props) {
    super(props);
    this.state = {value: ''};

    this.handleChange = this.handleChange.bind(this);
    this.handleSubmit = this.handleSubmit.bind(this);
  }

  handleChange(event) {
    this.setState({value: event.target.value});
  }

  handleSubmit(event) {
    alert('A name was submitted: ' + this.state.value);
    event.preventDefault();
  }

  render() {
    return (
      <form onSubmit={this.handleSubmit}>
        <label>
          Name:
          <input type="text" value={this.state.value} onChange={this.handleChange} />
        </label>
        <input type="submit" value="Submit" />
      </form>
    );
  }
}

Попробовать на CodePen

Поскольку атрибут value задан для нашего элемента формы, отображаемое значение всегда будет this.state.value, что делает состояние React источником истины. Поскольку handleChange выполняется при каждом нажатии клавиши для обновления состояния React, отображаемое значение будет обновляться по мере набора текста пользователем.

При использовании управляемого компонента значение поля ввода всегда определяется состоянием React. Хотя это означает, что вам нужно набрать немного больше кода, теперь вы можете передать значение другим элементам пользовательского интерфейса или сбросить его из других обработчиков событий.

Тег textarea

В HTML элемент <textarea> определяет свой текст своими дочерними элементами:

<textarea>
  Hello there, this is some text in a text area
</textarea>

В React элемент <textarea> использует атрибут value вместо этого. Таким образом, форма, использующая <textarea>, может быть написана очень похожим образом на форму, использующую однострочное поле ввода:

class EssayForm extends React.Component {
  constructor(props) {
    super(props);
    this.state = {
      value: 'Please write an essay about your favorite DOM element.'
    };

    this.handleChange = this.handleChange.bind(this);
    this.handleSubmit = this.handleSubmit.bind(this);
  }

  handleChange(event) {
    this.setState({value: event.target.value});
  }

  handleSubmit(event) {
    alert('An essay was submitted: ' + this.state.value);
    event.preventDefault();
  }

  render() {
    return (
      <form onSubmit={this.handleSubmit}>
        <label>
          Essay:
          <textarea value={this.state.value} onChange={this.handleChange} />
        </label>
        <input type="submit" value="Submit" />
      </form>
    );
  }
}

Обратите внимание, что this.state.value инициализируется в конструкторе, чтобы текстовое поле начинало работу с текстом.

Тег select

В HTML элемент <select> создает раскрывающийся список. Например, этот HTML создает раскрывающийся список вкусов:

<select>
  <option value="grapefruit">Grapefruit</option>
  <option value="lime">Lime</option>
  <option selected value="coconut">Coconut</option>
  <option value="mango">Mango</option>
</select>

Обратите внимание, что вариант «Кокос» изначально выбран из-за атрибута selected. React вместо использования этого атрибута selected использует атрибут value в корневом теге select. Это более удобно в управляемом компоненте, так как вам нужно обновить его только в одном месте. Например:

class FlavorForm extends React.Component {
  constructor(props) {
    super(props);
    this.state = {value: 'coconut'};

    this.handleChange = this.handleChange.bind(this);
    this.handleSubmit = this.handleSubmit.bind(this);
  }

  handleChange(event) {
    this.setState({value: event.target.value});
  }

  handleSubmit(event) {
    alert('Your favorite flavor is: ' + this.state.value);
    event.preventDefault();
  }

  render() {
    return (
      <form onSubmit={this.handleSubmit}>
        <label>
          Pick your favorite flavor:
          <select value={this.state.value} onChange={this.handleChange}>
            <option value="grapefruit">Grapefruit</option>
            <option value="lime">Lime</option>
            <option value="coconut">Coconut</option>
            <option value="mango">Mango</option>
          </select>
        </label>
        <input type="submit" value="Submit" />
      </form>
    );
  }
}

Попробовать на CodePen

В целом, это делает так, что <input type="text">, <textarea>, и <select> работают очень похоже — все они принимают атрибут value, который можно использовать для реализации управляемого компонента.

Примечание

Вы можете передать массив в атрибут value, что позволит вам выбрать несколько вариантов в теге select.

<select multiple={true} value={['B', 'C']}>

Тег file input

В HTML элемент <input type="file"> позволяет пользователю выбрать один или несколько файлов из хранилища устройства для загрузки на сервер или обработки JavaScript через API файлов.

<input type="file" />

Поскольку его значение является только для чтения, в React это неуправляемый компонент. Он рассматривается вместе с другими неуправляемыми компонентами позже в документации.

Обработка нескольких полей ввода

Когда вам нужно обработать несколько управляемых input элементов, вы можете добавить атрибут name к каждому элементу и позволить функции-обработчику выбрать, что делать, на основе значения event.target.name.

Например:

class Reservation extends React.Component {
  constructor(props) {
    super(props);
    this.state = {
      isGoing: true,
      numberOfGuests: 2
    };

    this.handleInputChange = this.handleInputChange.bind(this);
  }

  handleInputChange(event) {
    const target = event.target;
    const value = target.type === 'checkbox' ? target.checked : target.value;
    const name = target.name;

    this.setState({
      [name]: value
    });
  }

  render() {
    return (
      <form>
        <label>
          Is going:
          <input
            name="isGoing"            type="checkbox"
            checked={this.state.isGoing}
            onChange={this.handleInputChange} />
        </label>
        <br />
        <label>
          Number of guests:
          <input
            name="numberOfGuests"            type="number"
            value={this.state.numberOfGuests}
            onChange={this.handleInputChange} />
        </label>
      </form>
    );
  }
}

Попробовать на CodePen

Обратите внимание, как мы использовали синтаксис вычисления имени свойства ES6 вычисленных свойств имени для обновления ключа состояния, соответствующего данному имени поля ввода:

this.setState({
  [name]: value
});

Это эквивалентно следующему коду ES5:

var partialState = {};
partialState[name] = value;
this.setState(partialState);

Кроме того, поскольку setState() автоматически сливает частичное состояние в текущее состояние, нам потребовалось вызвать его только с измененными частями.

Значение управляемого поля ввода null

Указание свойства value для управляемого компонента предотвращает изменение ввода пользователем, если вы этого не хотите. Если вы указали value, но поле ввода все еще редактируемо, возможно, вы случайно установили value в undefined или null.

Следующий код демонстрирует это. (Поле ввода заблокировано сначала, но становится редактируемым через небольшую задержку.)

ReactDOM.render(<input value="hi" />, mountNode);

setTimeout(function() {
  ReactDOM.render(<input value={null} />, mountNode);
}, 1000);

Альтернативы управляемым компонентам

Иногда использование управляемых компонентов может быть утомительным, потому что вам нужно написать обработчик события для каждого способа изменения данных и передать все состояние ввода через компонент React. Это может стать особенно раздражающим при преобразовании существующего кода в React или интеграции приложения React с библиотекой, не являющейся React. В таких ситуациях вы можете ознакомиться с неуправляемыми компонентами, альтернативной техникой реализации форм ввода.

Полные решения

Если вы ищете полное решение, включая валидацию, отслеживание посещенных полей и обработку отправки формы, Formik — один из популярных вариантов. Однако он построен на тех же принципах управляемых компонентов и управления состоянием — поэтому не пренебрегайте изучением этих принципов.

Полезная ли эта страница?

© 2013–present Facebook Inc.
Licensed under the Creative Commons Attribution 4.0 International Public License.
https://17.reactjs.org/docs/forms.html

Spec-Zone.ru

Настройки Оффлайн Что нового Помощь О нас
Spec-Zone .ru
спецификации, руководства, описания, API