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

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

В этой части перевода учебного курса по 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: первое занятие по работе с формами

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

→ Оригинал

Но, как оказалось, у тех, кто занимается освоением React, работа с формами обычно вызывает определённые сложности. Формы являются достаточно важной частью веб-приложений. На этом занятии мы будем пользоваться стандартным проектом, создаваемым create-react-app, исходный вид файла App.js которого представлен ниже. Дело в том, что в React с формами работают по-особенному.

import React, from "react" class App extends Component { constructor() { super() this.state = {} } render() { return ( <div> Code goes here </div> ) }
} export default App

Обратите внимание на то, что для того, чтобы освоить материал этого занятия, вы должны быть знакомы с понятием состояния приложения. Если вы проработали все предыдущие занятия курса и самостоятельно выполняли практикумы, это значит, что вы обладаете знаниями, которые вам здесь понадобятся. Вот документация React, посвящённая формам. Рекомендуется, прежде чем продолжать, взглянуть на неё.

А именно, при обычном подходе формы описывают средствами HTML на веб страницах, после чего, пользуясь API DOM, взаимодействуют с ними из JavaScript. Итак, в React с формами работают немного не так, как при использовании обычного JavaScript. В React же, вместо того, чтобы ожидать ввода всех материалов в поля формы перед тем, как приступить к их программной обработке, за данными наблюдают постоянно, пользуясь состоянием приложения. В частности, по нажатию на кнопку отправки формы, собирают данные из полей, заполненных пользователем, и готовят их к отправке на сервер, проверяя их, и, при необходимости, сообщая пользователю о том, что он заполнил какие-то поля неверно. В результате в React-приложении мы можем оперативно работать с самой свежей версией того, что пользователь вводит в поля формы. Это, например, сводится к тому, что каждый символ, введённый пользователем с клавиатуры, сразу же попадает в состояние. Для того, чтобы продемонстрировать эту идею в действии, начнём с описания формы, содержащей обычное текстовое поле.

При обычном подходе такая форма имела бы кнопку, по нажатию на которую программные механизмы приложения приступают к обработке данных, введённых в эту форму. Для этого, в коде, который возвращает метод render(), опишем форму. Для этого нам понадобится обрабатывать событие поля onChange. В нашем же случае данные, введённые пользователем в поле, будут поступать в приложение по мере их ввода. Для этого нам понадобится, во-первых, узнать, что содержится в поле, и во-вторых — поместить эти данные в состояние. В обработчике этого события (назовём его handleChange()) мы будем обновлять состояние, записывая в него то, что введено в поле. Это поле мы собираемся использовать для хранения имени (first name) пользователя, поэтому назовём соответствующее свойство firstName и инициализируем его пустой строкой. В состоянии создадим свойство, хранящее содержимое поля.

Так как предыдущее значение, которое хранилось в свойстве состояния firstName, нас не интересует, мы можем просто передать этой функции объект с новым значением firstName. После этого, в конструкторе, привяжем обработчик события handleChange() к this и в коде обработчика воспользуемся функцией setState(). Что должно быть записано в это свойство?

В нашем случае обработчику передаётся объект события (event). Если вспомнить то, как работают обработчики событий в JavaScript, то окажется, что при их вызове им передаются некие предопределённые параметры. Текстовое поле, событие onChange которого мы обрабатываем, представлен в этом объекте в виде event.target. Он и содержит интересующие нас данные. А к содержимому этого поля можно обратиться, воспользовавшись конструкцией event.target.value.

Теперь, в методе render(), выведем то, что будет храниться в состоянии и посмотрим на то, что у нас получилось.

Вот код, реализующий вышеописанные идеи.

import React, {Component} from "react" class App extends Component { constructor() { super() this.state = { firstName: "" } this.handleChange = this.handleChange.bind(this) } handleChange(event) { this.setState({ firstName: event.target.value }) } render() { return ( <form> <input type="text" placeholder="First Name" onChange={this.handleChange} /> <h1>{this.state.firstName}</h1> </form> ) }
} export default App

Вот как всё это выглядит в браузере.

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

Каждый символ, введённый в поле, тут же появляется в элементе <h1>, присутствующем на странице.

Очевидно, что для того, чтобы наладить правильную обработку данных, вводимых в это поле, нам понадобится добавить в состояние ещё одно свойство и поработать над механизмами, обновляющими состояние при вводе данных в поле. Подумаем теперь о том, как добавить на форму ещё одно поле, для фамилии (last name) пользователя.

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

После этого мы сможем, работая с объектом события, который передаётся обработчику, узнать имя поля, изменения в котором привели к его вызову, и воспользоваться этим именем. Для того чтобы в одном и том же обработчике событий различать поля, при изменении которых он вызывается, мы назначим полям свойства name, которые сделаем точно такими же, какими сделаны имена свойств, используемых для хранения данных полей в состоянии (firstName и lastName). Вот код, который реализует эту возможность: Мы будем пользоваться им, задавая имя свойства состояния, в которое хотим внести обновлённые данные.

import React, {Component} from "react" class App extends Component { constructor() { super() this.state = { firstName: "", lastName: "" } this.handleChange = this.handleChange.bind(this) } handleChange(event) { this.setState({ [event.target.name]: event.target.value }) } render() { return ( <form> <input type="text" name="firstName" placeholder="First Name" onChange={this.handleChange} /> <br /> <input type="text" name="lastName" placeholder="Last Name" onChange={this.handleChange} /> <h1>{this.state.firstName} {this.state.lastName}</h1> </form> ) }
} export default App

Обратите внимание на то, что, задавая имя свойства объекта, передаваемого setState(), мы заключаем конструкцию event.target.name в прямоугольные скобки.

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

На страницу теперь выводится то, что вводится в первое поле, и то, что вводится во второе поле.

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

Здесь же мы затронем ещё одну тему, которая имеет отношение к так называемым «управляемым компонентам» (controlled component), о которых вы, если посмотрели документацию React по формам, уже кое-что читали. О работе с другими элементами форм мы поговорим на следующем занятии.

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

import React, {Component} from "react" class App extends Component { constructor() { super() this.state = { firstName: "", lastName: "" } this.handleChange = this.handleChange.bind(this) } handleChange(event) { this.setState({ [event.target.name]: event.target.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} /> <h1>{this.state.firstName} {this.state.lastName}</h1> </form> ) }
} export default App

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

Вот как выглядит код обработчика событий onChange сейчас: Хочу дать один совет, который избавит вас в будущем от ошибок, которые очень тяжело отлаживать.

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

Рекомендуется, вместо прямого обращения к свойствам объекта event при конструировании объекта, передаваемого setState(), заранее извлечь из него то, что нужно:

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

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

Итоги

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

Уважаемые читатели! Пользуетесь ли вы какими-нибудь дополнительными библиотеками при работе с формами в React?


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

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

*

x

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

Прыжки китайского «Кузнечика» от LinkSpace

Китайская частная космическая компания LinkSpace построила тестовый ракетный стенд вертикального взлета и посадки, аналогичный «Кузнечику» от SpaceX, и с января этого года проводит все более сложные испытания. После тестов зависания на привязи компания перешла к полноценным подскокам, 27 марта поднявшись ...

Искусственный интеллект улучшает качество графики старых видеоигр и делает это действительно хорошо

Недавно стало известно еще об одной задаче, которую ИИ решает очень хорошо. Технологии искусственного интеллекта постепенно развиваются, помогая решать задачи и проблемы самых разных сфер — от бизнеса до медицины и развлечений. Речь идет об игровых модах — как оказалось, ...