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

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

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

В React есть специальные термины, используемые для описания этих двух способов работы с формами. Элемент формы, который управляет своим собственным состоянием, называется «неуправляемым компонентом», тогда как элемент формы, состояние которого управляется React, называется «управляемый компонент». .

В управляемом компоненте данные формы обрабатываются компонентом React.
В неконтролируемом компоненте данные формы обрабатываются самой DOM.

Неконтролируемые компоненты

Мы начнем с HTML, рассмотрев, как работать с элементами формы, которые управляют своим собственным состоянием.

Чтобы научиться работать с неконтролируемыми компонентами в React, мы создадим новый файл с именем uncontrolledform.html. В разделе head файла мы загружаем React, ReactDOM и Babel (в указанном порядке), используя их ссылки CDN. В разделе body у нас есть пустой div с id равным root, где мы будем отображать наше приложение React. Мы, как и раньше, напишем наш код внутри тега <script>. Вот как выглядит наш код на данный момент:

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

Ссылки

Ссылки предоставляют способ доступа к узлам DOM или элементам React, созданным в методе рендеринга.

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

В приведенном выше фрагменте мы создаем компонент класса с именем UncontrolledForm. В методе constructor() мы создаем ref для хранения ссылки на элемент DOM «Имя» <input>.

ПРИМЕЧАНИЕ. React.createRef() API был представлен в React версии 16.3. Если бы мы использовали более раннюю версию React, мы бы вместо этого использовали callback refs.

Обратите внимание также, как мы используем this.nameInput для определения нашего nameInput ref как свойства экземпляра. Это позволяет нам ссылаться на ссылку по всему классу.

В методе render() мы сообщаем React, что хотим связать HTML-элемент <input> с nameInput ref, который мы создали в конструкторе. Когда ссылка передается элементу в render, ссылка на узел DOM становится доступной в свойстве current ссылки, в нашем случае как this.nameInput.current. React назначит элемент DOM свойству current при монтировании компонента и вернет его null при размонтировании. ref обновления происходят до componentDidMount или componentDidUpdate методов жизненного цикла.

В приведенном выше фрагменте показано, как мы можем получить доступ к значению ввода имени с помощью ссылки ref. В методе render() мы добавляем обработчик события onSubmit к элементу <form>. Это сработает при отправке формы. Мы связываем метод handleSubmit в конструкторе, чтобы получить доступ к правильному this. Внутри метода handleSubmit() мы сначала вызываем метод event.preventDefault(), чтобы предотвратить полную перезагрузку страницы. Мы выводим в консоль значение ввода текста имени, получая доступ к нему из this.nameInput.current.value.

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

Аналогично, <input type="checkbox"> и <input type="radio"> поддерживают атрибут defaultChecked, тогда как <select> и <textarea> поддерживают атрибут defaultValue.

Вот полный код этого примера:

БОКОВОЕ ПРИМЕЧАНИЕ. Компонент UncontrolledForm, указанный выше, также можно было бы записать как функциональный компонент, а не следующим образом:

Контролируемые компоненты

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

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

Основное отличие состоит в том, что управляемый ввод принимает свое текущее значение как опору и имеет обработчик событий onChange для обновления этого значения, когда пользователь вводит ввод.

В методе constructor() мы добавляем свойство name в состояние, которое будет отслеживать текущее значение нашего текстового ввода. Мы также привязываем this к нашему новому методу handleChange.

Каждый раз, когда значение ввода изменяется (это происходит, когда мы вводим текст в поле ввода), вызывается обработчик this.handleChange. Это обновляет значение this.state.name с помощью метода setState() и устанавливает новое значение для содержимого поля ввода. Вызов setState() запускает повторную визуализацию, и значение ввода обновляется до текущего значения this.state.name. Теперь состояние компонента (данные) и пользовательский интерфейс (значение, отображаемое во входных данных) всегда синхронизированы, а состояние React является единственным источником истины.

Вот полный код этого примера:

Другие элементы формы

Мы продолжим и посмотрим, как работать с элементами формы <input type="checkbox">, <input type="radio">, <select> и <textarea> как с управляемыми элементами.

Вот обновленный код:

Мы добавили три флажка, две переключатели, раскрывающийся список и текстовое поле. Мы добавили опору name к текстовому вводу, переключателям, раскрывающемуся списку выбора и текстовой области, чтобы мы могли повторно использовать один onChange обработчик событий и динамически обновлять различные значения в состоянии. В методе handleChange мы используем синтаксис ES6 вычисляемое имя свойства для обновления ключа состояния, соответствующего заданному имени входа, полученному из event.target.name.

Если мы хотим, чтобы наши элементы формы начинались с некоторых значений по умолчанию, мы инициализируем их соответствующие значения в состоянии, например. флажок «Язык CSS» будет выбран в начале, в то время как для выбора будет выбран «промежуточный» вариант.

Это четвертая часть серии статей, посвященных вводным концепциям React.