Главная » Хабрахабр » [Перевод] Учебный курс по React, часть 24: второе занятие по работе с формами

[Перевод] Учебный курс по React, часть 24: второе занятие по работе с формами

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

image

→ Часть 1: обзор курса, причины популярности React, ReactDOM и JSX
→ Часть 2: функциональные компоненты
→ Часть 3: файлы компонентов, структура проектов
→ Часть 4: родительские и дочерние компоненты
→ Часть 5: начало работы над TODO-приложением, основы стилизации
→ Часть 6: о некоторых особенностях курса, JSX и JavaScript
→ Часть 7: встроенные стили
→ Часть 8: продолжение работы над TODO-приложением, знакомство со свойствами компонентов
→ Часть 9: свойства компонентов
→ Часть 10: практикум по работе со свойствами компонентов и стилизации
→ Часть 11: динамическое формирование разметки и метод массивов map
→ Часть 12: практикум, третий этап работы над TODO-приложением
→ Часть 13: компоненты, основанные на классах
→ Часть 14: практикум по компонентам, основанным на классах, состояние компонентов
→ Часть 15: практикумы по работе с состоянием компонентов
→ Часть 16: четвёртый этап работы над TODO-приложением, обработка событий
→ Часть 17: пятый этап работы над TODO-приложением, модификация состояния компонентов
→ Часть 18: шестой этап работы над TODO-приложением
→ Часть 19: методы жизненного цикла компонентов
→ Часть 20: первое занятие по условному рендерингу
→ Часть 21: второе занятие и практикум по условному рендерингу
→ Часть 22: седьмой этап работы над TODO-приложением, загрузка данных из внешних источников
→ Часть 23: первое занятие по работе с формами
→ Часть 24: второе занятие по работе с формами

Занятие 42. Работа с формами, часть 2

→ Оригинал

К настоящему моменту мы рассмотрели лишь работу с обычными текстовыми полями ввода.
Вот код компонента App, с которого мы начнём сегодняшние эксперименты: На этом занятии мы поговорим о полях для ввода многострочного текста, о флажках, о переключателях (их ещё называют «радиокнопками») и о полях со списками.

import React, from "react" class App extends Component { constructor() { super() this.state = { firstName: "", lastName: "" } this.handleChange = this.handleChange.bind(this) } handleChange(event) { const {name, value} = event.target this.setState({ [name]: value }) } render() { return ( <form> <input type="text" value={this.state.firstName} name="firstName" placeholder="First Name" onChange={this.handleChange} /> <br /> <input type="text" value={this.state.lastName} name="lastName" placeholder="Last Name" onChange={this.handleChange} /> { /** * Другие полезные элементы форм: * * <textarea /> * <input type="checkbox" /> * <input type="radio" /> * <select> и <option> */ } <h1>{this.state.firstName} {this.state.lastName}</h1> </form> ) }
} export default App

Вот как выглядит страница приложения в браузере на данном этапе работы.

Страница приложения в браузере

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

Начнём с поля для ввода многострочного текста — элемента textarea. В вышеприведённом коде есть закомментированный фрагмент, в котором перечислены элементы, о которых мы будем говорить. Если вы раньше, строя обычные HTML-формы, уже пользовались этим элементом, вы знаете, что это — не самозакрывающийся тег, как было в случае с элементом input. Вероятно, понять то, как с ним работать, легче всего. У него есть открывающая и закрывающая части.
Добавим на форму этот элемент, вставив, сразу после комментария, следующий код:

<br />
<textarea></textarea>

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

Поле для ввода текста на странице

Благодаря атрибутам rows и cols можно, при описании этого элемента, указывать его размеры. Как видно, это поле немного выше обычных полей, пользователь может менять его размеры, пользуясь маркером в его правой нижней части. В React работа с такими элементами сделана максимально похожей на работу с элементами input, о которых мы говорили в прошлый раз. В обычном HTML, если нужно, чтобы после вывода этого поля в нём уже был какой-то текст, делается это путём ввода нужного текста между открывающим и закрывающим тегами элемента. То есть код для вывода поля на страницу можно изменить следующим образом: А именно, в React тег textarea является самозакрывающимся.

<textarea />

В этом теге можно использовать атрибут value, причём, работа с ним осуществляется точно так же, как и с таким же атрибутом обычных текстовых полей. Благодаря этому достигается единообразие в работе с разными элементами, и, кроме того, облегчается обновление содержимого полей путём обновления свойств состояния, привязанных к таким полям. Приведём состояние кода поля к такому виду:

<textarea value={"Some default value"}/>

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

Текст, появившийся в поле

Флажок — это элемент управления input, в качестве типа которого указан checkbox. К работе с полем для ввода многострочного текста мы ещё вернёмся, а пока поговорим о флажках. Вот как выглядит его описание:

<input type="checkbox" />

Вот как выглядит флажок, описанный этой разметкой, на странице.

Флажок

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

Приведём состояние компонента к такому виду:

this.state = { firstName: "", lastName: "", isFriendly: true
}

Код описания флажка изменим следующим образом:

<input type="checkbox" checked={this.state.isFriendly}
/>

После этого на страницу будет выведен установленный флажок.

Установленный флажок

Дело в том, что флажок привязан к соответствующей переменной, хранящейся в состоянии, в результате при попытке, в нашем случае, снять его, React, проверяя состояние, и обнаруживая, что свойство isFriendly установлено в true, не даёт этого сделать. Правда, сейчас он не будет реагировать на щелчки по нему. При этом в консоль будет выводиться предупреждение о том, что мы не предусмотрели механизм изменения поля (обработчик события onChange) и оно выведено в состоянии «только для чтения».

Предупреждение в консоли

Сейчас он используется для работы с текстовыми полями. Мы вполне можем написать особый метод для работы с флажком, но в коде нашего компонента уже есть метод handleChange(). Для этого сначала назначим вышеуказанный метод в качестве обработчика события onChange флажка и назначим флажку имя, соответствующее имени свойства состояния, относящегося к флажку. Подумаем о том, как воспользоваться им и для работы с флажком. Кроме того, подпишем флажок, воспользовавшись тегом label:

<label> <input type="checkbox" name="isFriendly" checked={this.state.isFriendly} onChange={this.handleChange} /> Is friendly?
</label>

В методе handleChange(), код которого показан ниже, мы, при работе с текстовыми полями, выясняли имя элемента (name) и его содержимое (value), после чего обновляли состояние, записывая в него то, что было у поля с определённым именем в его атрибуте value:

handleChange(event) { const {name, value} = event.target this.setState({ [name]: value })
}

Теперь нам нужно разобраться с тем, как быть с флажком, атрибута value у которого нет. У него есть лишь атрибут checked, который может принимать только значения true или false. В результате нам, для того чтобы использовать метод handleChange() для работы с флажком, нужно проверить, является ли элемент, для которого вызван этот обработчик, флажком. Для того чтобы выполнить эту проверку — вспомним, что в качестве типа (type) элемента input, представляющего флажок, задано значение checkbox. Для того чтобы проверить это значение, можно обратиться к свойству type элемента event.target. Извлечём это свойство из event.target, а также — свойство checked, воспользовавшись следующей конструкцией:

const {name, value, type, checked} = event.target

Теперь мы можем проверить значение константы type и выяснить, является ли элемент, для которого вызван обработчик события, флажком. Если это так — мы запишем в состояние то, что оказалось в константе checked. Не забудем при этом сохранить код, ответственный за работу с текстовыми полями. В результате код handleChange() приобретёт следующий вид:

handleChange(event) { const {name, value, type, checked} = event.target type === "checkbox" ? this.setState({ [name]: checked }) : this.setState({ [name]: value })
}

После этого проверим работу флажка.

Проверка работы флажка

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

<textarea value={"Some default value"} onChange={this.handleChange}
/>

Это приведёт к исчезновению уведомления, хотя другие механизмы, позволяющие работать с этим полем средствами компонента, мы не реализовали (не указали имя для поля, не добавили в состояние соответствующее свойство). Вы можете реализовать эти возможности самостоятельно. Теперь поговорим о переключателях.

Здесь имеется в виду то, что у переключателей есть и атрибут value, и атрибут checked. Их можно представить в виде комбинации элементов input типов text и checkbox. Вот как это выглядит: Добавим в нашу форму пару переключателей, создав их код на основе кода описания флажка.

<label> <input type="radio" name="gender" value="male" checked={this.state.isFriendly} onChange={this.handleChange} /> Male
</label>
<br />
<label> <input type="radio" name="gender" value="female" checked={this.state.isFriendly} onChange={this.handleChange} /> Female
</label>

Мы создали этот код на основе кода описания флажка и кое-что ещё не отредактировали. Поэтому переключатели странно себя ведут. В частности, если флажок снят, то и тот и другой переключатели находятся в «выключенном» состоянии, а если установить флажок — один из них оказывается «включенным». Подобные ошибки можно предупредить, внимательно относясь к коду элементов в том случае, если он создаётся на основе кода уже существующих элементов. Сейчас мы это исправим.
Обратите внимание на то, что у этих двух элементов одно и то же имя — gender. Переключатели с одним и тем же именем формируют группу. Выбранным может быть лишь один переключатель, входящий в такую группу.

Переключатели должны поддерживать синхронизированное, в пределах группы, изменение собственного состояния. При настройке переключателей нельзя просто указать на то, что их значение checked устанавливается, скажем, в true, если некое свойство состояния равняется true. Это условие в нашем случае будет представлено сравнением свойства состояния this.state.gender со строкой male или female. Вместо этого значение checked переключателей устанавливается по условию. В коде описания переключателей это выглядит так:

<label> <input type="radio" name="gender" value="male" checked={this.state.gender === "male"} onChange={this.handleChange} /> Male
</label>
<br />
<label> <input type="radio" name="gender" value="female" checked={this.state.gender === "female"} onChange={this.handleChange} /> Female
</label>

Теперь добавим в состояние новое свойство, gender, инициализировав его пустой строкой:

this.state = { firstName: "", lastName: "", isFriendly: false, gender: ""
}

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

<h2><font color="#3AC1EF">You are a {this.state.gender}</font></h2>

Тут, вероятно, стоит внедрить некий механизм условного рендеринга. Это позволит, при открытии страницы, когда ни один из переключателей не выбран, сделать так, чтобы на ней не выводился бы текст You are a, но мы этого делать не будем, хотя вы вполне можете реализовать это самостоятельно. Взглянем теперь на то, что у нас получилось.

Переключатели на странице приложения

В частности, это касается запоминания особенностей разных элементов управления. Всё то, о чём мы тут говорили, может показаться достаточно сложным. Например — библиотеку formik. Для того чтобы упростить работу с формами, можно применять специализированные библиотеки. Эта библиотека значительно упрощает процесс разработки форм в React-приложениях.

Теперь поговорим о полях со списками.

В обычном HTML при описании полей со списком используются такие конструкции:

<select> <option></option> <option></option> <option></option>
<select/>

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

Для этого в атрибут value элемента select можно поместить следующую конструкцию: value={this.state.favColor}. Предположим, мы хотим создать поле со списком, позволяющее пользователю выбирать его любимый цвет. Теперь добавим favColor в состояние: Сюда будут попадать те значения, которые будет выбирать пользователь.

this.state = { firstName: "", lastName: "", isFriendly: false, gender: "", favColor: "blue"
}

Далее, оснастим поле со списком обработчиком события onChange и дадим ему имя. Также назначим значения value элементам options поля со списком и введём текст, который будет выводиться в поле.

Вот как выглядит настроенный элемент select с подписью:

<label>Favorite Color:</label>
<select value={this.state.favColor} onChange={this.handleChange} name="favColor"
> <option value="blue">Blue</option> <option value="green">Green</option> <option value="red">Red</option> <option value="orange">Orange</option> <option value="yellow">Yellow</option>
</select>

Теперь добавим в форму ещё одну надпись, выводящую любимый цвет пользователя:

<h2><font color="#3AC1EF">Your favorite color is {this.state.favColor}</font></h2>

Пришло время испытать поле со списком.

Поле со списком

Как видно, хотя наша форма и не блещет изысками дизайна, элементы управления, размещённые на ней, работают так, как ожидается.

Именно такая схема работы используется и в нашем случае. Благодаря тому, как в React организованы API элементов управления, несложно сделать так, чтобы для обработки их событий применялся бы один и тот же обработчик. Единственная особенность нашего обработчика handleChange() заключается в том, что нам приходится по-особенному обрабатывать события флажка.

Можно выделить два подхода к выполнению подобных действий. Теперь поговорим об отправке формы или об обработке введённых в неё значений после завершения её заполнения. При применении любого из них форму стоит оснастить кнопкой:

<button>Submit</button>

В HTML5, если в форме будет найден элемент button, он будет действовать как старый элемент input с типом submit. Если по этой кнопке щёлкнуть — будет вызвано событие самой формы onSubmit. Если нужно что-то сделать после завершения заполнения формы, можно добавить обработчик события onClick к кнопке, но, например, лично я предпочитаю обрабатывать подобные события на уровне формы, назначая ей обработчик события onSubmit:

<form onSubmit={this.handleSubmit}>

Метод, используемый в качестве обработчика этого события, ещё не написан. Это — обычный обработчик события, который, например, обращаясь к некоему API, передаёт ему данные формы.

Итоги

На этом занятии мы завершаем разговор о работе с формами в React. В следующий раз вас ждёт практическая работа по этой теме.

Уважаемые читатели! Если вы пробовали использовать библиотеку formik для создания форм в React — просим об этом рассказать.


Оставить комментарий

Ваш email нигде не будет показан
Обязательные для заполнения поля помечены *

*

x

Ещё Hi-Tech Интересное!

[Из песочницы] ВИЧ – методы лечения от первых лекарств до сегодняшнего дня

Прежде, чем приступить к изложению материала, хотелось бы сказать несколько слов о себе: участник сообществ по борьбе с отрицанием ВИЧ („ВИЧ/СПИД диссидентством“): в 2016-2018 годах „ВИЧ/СПИД диссиденты и их дети“, с 2018 года – „ВИЧ/СПИД отрицание и альтернативная медицина“. Это ...

Изюминки прошедшей Moscow Python Conf++ 2019: трансформация в площадку для общения

Самыми горячими темами Moscow Python Conf++ оказались асинхронная разработка, а также сопоставление Python, его лучших практик и инструментария с аналогами из других языков, и его место в ландшафте современной разработки. Плюс мы пригласили выступить Бенджамина Петерсона, одного из разработчиков CPython, ...