JS: React

Теория: Формы

Формы в HTML работают немного не так, как формы в React. Это связано с тем, что в HTML они имеют свое внутреннее состояние — место, в котором хранятся значения форм, тексты, выбранные опции и тому подобное.

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

Форма выше при каждом изменении поля name изменяет свое внутреннее состояние, которое будет отправлено по нужному адресу при отправке.

В отличие от прямой работы с DOM (даже через jQuery), в React источником правды является состояние, а не DOM. Формы не являются исключением. Любое изменение в форме, посимвольно, если это ввод, должно быть перенесено в состояние. А элементы форм, чьи данные хранятся в состоянии React, называются управляемыми компонентами (controlled components).

class TextInput extends React.Component {
  constructor(props) {
    super(props);
    this.state = { text: props.text };
  }

  handleSubmit = (e) => {
    e.preventDefault();
    alert(`A name was submitted: ${this.state.text}`);
  };

  handleChange = (e) => {
    this.setState({ text: e.target.value });
  };

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

const mountNode = document.getElementById('react-root');
const root = ReactDOM.createRoot(mountNode);
root.render(<TextInput text="initial text" />);

Попрактиковаться

В коде выше на каждое изменение в элементе input происходит извлечение содержимого через e.target.value и запись его в React. Последующая отправка не нуждается в самой форме, так как все данные уже есть в состоянии. Поэтому при отправке формы достаточно получить нужные данные из объекта-состояния и отправить их, например, на сервер. Обратите внимание: элемент формы становится управляемым (controlled components) только когда происходит подстановка его значения из React: <input value={this.state.text} />.

Один из множества плюсов управляемых компонентов в том, что становится крайне легко проводить фильтрацию или валидацию. Например, если необходимо вводить данные в верхнем регистре (например, при вводе данных карты), то сделать это можно так:

handleChange = (e) => {
  this.setState({ value: e.target.value.toUpperCase() })
}

В противовес управляемым компонентам, React позволяет использовать неуправляемые компоненты (uncontrolled components). При таком подходе состояние формы хранится в самом DOM. Этот способ нужен исключительно для интеграции со сторонними библиотеками или для работы с устаревшим («легаси») кодом. В нормальной ситуации он не понадобится.

Текстовая область

В HTML значение <textarea> устанавливается как его содержимое:

<textarea>
  Like this
</textarea>

В React для этого используется атрибут value:

class Editor extends React.Component {
  constructor(props) {
    super(props);
    this.state = { text: props.text };
  }

  onChange = (e) => {
    this.setState({ text: e.target.value });
  };

  render() {
    return (
      <textarea
        onChange={this.onChange}
        value={this.state.text}
      />
    );
  }
}

const mountNode = document.getElementById('react-root');
const root = ReactDOM.createRoot(mountNode);
root.render(<Editor text="initial text" />);

Попрактиковаться

Стоит отметить, что событие onChange в React работает так, как ожидается, в отличие от onChange в HTML, который срабатывает только когда элемент теряет фокус. Поэтому событие гарантированно происходит на каждое изменение. При этом данные из элемента формы извлекаются обычным способом через e.target.value. Ну а дальше все по старой схеме — данные обновляются в состоянии.

Выпадающий список

В HTML текущий элемент выбирается с помощью атрибута selected, проставленного на нужном option.

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

React предлагает другой способ: необходимо проставить атрибут value компонента select в нужное значение.

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

  handleChange = (e) => {
    this.setState({ value: e.target.value });
  };

  handleSubmit = (e) => {
    e.preventDefault();
    alert(`Your favorite flavor is: ${this.state.value}`);
  };

  render() {
    return (
      <form onSubmit={this.handleSubmit}>
        <label>
          Pick your favorite La Croix flavor:
          <select value={this.state.value} onChange={this.handleChange}>
            <option value="">Select a fruit</option>
            <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>
    );
  }
}

const mountNode = document.getElementById('react-root');
const root = ReactDOM.createRoot(mountNode);
root.render(<FlavorForm />);

Попрактиковаться

Чекбокс и радиокнопка

Оба этих типа поддерживают атрибут checked. Если он выставлен, то элемент отмечается выбранным.

<input name="isGoing" type="checkbox" checked={this.state.isGoing} onChange={this.handleChange} />

Шаблонный код

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

Завершено

0 / 30