- PVSM.RU - https://www.pvsm.ru -
В этой части перевода учебного курса по React мы поговорим о работе с формами. В частности, сегодняшнее занятие посвящено организации взаимодействия компонентов и текстовых полей.
→ Часть 1: обзор курса, причины популярности React, ReactDOM и JSX [2]
→ Часть 2: функциональные компоненты [3]
→ Часть 3: файлы компонентов, структура проектов [4]
→ Часть 4: родительские и дочерние компоненты [5]
→ Часть 5: начало работы над TODO-приложением, основы стилизации [6]
→ Часть 6: о некоторых особенностях курса, JSX и JavaScript [7]
→ Часть 7: встроенные стили [8]
→ Часть 8: продолжение работы над TODO-приложением, знакомство со свойствами компонентов [9]
→ Часть 9: свойства компонентов [10]
→ Часть 10: практикум по работе со свойствами компонентов и стилизации [11]
→ Часть 11: динамическое формирование разметки и метод массивов map [12]
→ Часть 12: практикум, третий этап работы над TODO-приложением [13]
→ Часть 13: компоненты, основанные на классах [14]
→ Часть 14: практикум по компонентам, основанным на классах, состояние компонентов [15]
→ Часть 15: практикумы по работе с состоянием компонентов [16]
→ Часть 16: четвёртый этап работы над TODO-приложением, обработка событий [17]
→ Часть 17: пятый этап работы над TODO-приложением, модификация состояния компонентов [18]
→ Часть 18: шестой этап работы над TODO-приложением [19]
→ Часть 19: методы жизненного цикла компонентов [20]
→ Часть 20: первое занятие по условному рендерингу [21]
→ Часть 21: второе занятие и практикум по условному рендерингу [22]
→ Часть 22: седьмой этап работы над TODO-приложением, загрузка данных из внешних источников [23]
→ Часть 23: первое занятие по работе с формами [1]
→ Оригинал [24]
Формы являются достаточно важной частью веб-приложений. Но, как оказалось, у тех, кто занимается освоением React, работа с формами обычно вызывает определённые сложности. Дело в том, что в React с формами работают по-особенному. На этом занятии мы будем пользоваться стандартным проектом, создаваемым create-react-app, исходный вид файла App.js
которого представлен ниже.
import React, {Component} from "react"
class App extends Component {
constructor() {
super()
this.state = {}
}
render() {
return (
<div>
Code goes here
</div>
)
}
}
export default App
Обратите внимание на то, что для того, чтобы освоить материал этого занятия, вы должны быть знакомы с понятием состояния приложения. Если вы проработали все предыдущие занятия курса и самостоятельно выполняли практикумы, это значит, что вы обладаете знаниями, которые вам здесь понадобятся. Вот [25] документация React, посвящённая формам. Рекомендуется, прежде чем продолжать, взглянуть на неё.
Итак, в React с формами работают немного не так, как при использовании обычного JavaScript. А именно, при обычном подходе формы описывают средствами HTML на веб страницах, после чего, пользуясь API DOM, взаимодействуют с ними из JavaScript. В частности, по нажатию на кнопку отправки формы, собирают данные из полей, заполненных пользователем, и готовят их к отправке на сервер, проверяя их, и, при необходимости, сообщая пользователю о том, что он заполнил какие-то поля неверно. В React же, вместо того, чтобы ожидать ввода всех материалов в поля формы перед тем, как приступить к их программной обработке, за данными наблюдают постоянно, пользуясь состоянием приложения. Это, например, сводится к тому, что каждый символ, введённый пользователем с клавиатуры, сразу же попадает в состояние. В результате в React-приложении мы можем оперативно работать с самой свежей версией того, что пользователь вводит в поля формы. Для того, чтобы продемонстрировать эту идею в действии, начнём с описания формы, содержащей обычное текстовое поле.
Для этого, в коде, который возвращает метод render()
, опишем форму. При обычном подходе такая форма имела бы кнопку, по нажатию на которую программные механизмы приложения приступают к обработке данных, введённых в эту форму. В нашем же случае данные, введённые пользователем в поле, будут поступать в приложение по мере их ввода. Для этого нам понадобится обрабатывать событие поля onChange
. В обработчике этого события (назовём его handleChange()
) мы будем обновлять состояние, записывая в него то, что введено в поле. Для этого нам понадобится, во-первых, узнать, что содержится в поле, и во-вторых — поместить эти данные в состояние. В состоянии создадим свойство, хранящее содержимое поля. Это поле мы собираемся использовать для хранения имени (first name) пользователя, поэтому назовём соответствующее свойство firstName
и инициализируем его пустой строкой.
После этого, в конструкторе, привяжем обработчик события handleChange()
к this
и в коде обработчика воспользуемся функцией setState()
. Так как предыдущее значение, которое хранилось в свойстве состояния firstName
, нас не интересует, мы можем просто передать этой функции объект с новым значением firstName
. Что должно быть записано в это свойство?
Если вспомнить то, как работают обработчики событий в JavaScript, то окажется, что при их вызове им передаются некие предопределённые параметры. В нашем случае обработчику передаётся объект события (event
). Он и содержит интересующие нас данные. Текстовое поле, событие 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), о которых вы, если посмотрели документацию [25] 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 [26] в документации React.
На этом занятии состоялось ваше первое знакомство с механизмами работы с формами в React. В следующий раз мы продолжим эту тему.
Уважаемые читатели! Пользуетесь ли вы какими-нибудь дополнительными библиотеками при работе с формами в React?
Автор: ru_vds
Источник [27]
Сайт-источник PVSM.RU: https://www.pvsm.ru
Путь до страницы источника: https://www.pvsm.ru/javascript/311924
Ссылки в тексте:
[1] Image: https://habr.com/ru/company/ruvds/blog/443214/
[2] Часть 1: обзор курса, причины популярности React, ReactDOM и JSX: https://habr.com/post/432636/
[3] Часть 2: функциональные компоненты: https://habr.com/post/433400/
[4] Часть 3: файлы компонентов, структура проектов: https://habr.com/post/433404/
[5] Часть 4: родительские и дочерние компоненты: https://habr.com/company/ruvds/blog/434118/
[6] Часть 5: начало работы над TODO-приложением, основы стилизации: https://habr.com/company/ruvds/blog/434120/
[7] Часть 6: о некоторых особенностях курса, JSX и JavaScript: https://habr.com/company/ruvds/blog/435466/
[8] Часть 7: встроенные стили: https://habr.com/company/ruvds/blog/435468/
[9] Часть 8: продолжение работы над TODO-приложением, знакомство со свойствами компонентов: https://habr.com/company/ruvds/blog/435470/
[10] Часть 9: свойства компонентов: https://habr.com/company/ruvds/blog/436032/
[11] Часть 10: практикум по работе со свойствами компонентов и стилизации: https://habr.com/company/ruvds/blog/436890/
[12] Часть 11: динамическое формирование разметки и метод массивов map: https://habr.com/company/ruvds/blog/436892/
[13] Часть 12: практикум, третий этап работы над TODO-приложением: https://habr.com/company/ruvds/blog/437988/
[14] Часть 13: компоненты, основанные на классах: https://habr.com/ru/company/ruvds/blog/437990/
[15] Часть 14: практикум по компонентам, основанным на классах, состояние компонентов: https://habr.com/ru/company/ruvds/blog/438986/
[16] Часть 15: практикумы по работе с состоянием компонентов: https://habr.com/ru/company/ruvds/blog/438988/
[17] Часть 16: четвёртый этап работы над TODO-приложением, обработка событий: https://habr.com/ru/company/ruvds/blog/439982/
[18] Часть 17: пятый этап работы над TODO-приложением, модификация состояния компонентов: https://habr.com/ru/company/ruvds/blog/439984/
[19] Часть 18: шестой этап работы над TODO-приложением: https://habr.com/ru/company/ruvds/blog/440662/
[20] Часть 19: методы жизненного цикла компонентов: https://habr.com/ru/company/ruvds/blog/441578/
[21] Часть 20: первое занятие по условному рендерингу: https://habr.com/ru/company/ruvds/blog/441580/
[22] Часть 21: второе занятие и практикум по условному рендерингу: https://habr.com/ru/company/ruvds/blog/443210/
[23] Часть 22: седьмой этап работы над TODO-приложением, загрузка данных из внешних источников: https://habr.com/ru/company/ruvds/blog/443212/
[24] Оригинал: https://scrimba.com/p/p7P5Hd/cW8Jdfy
[25] Вот: https://reactjs.org/docs/forms.html
[26] SyntheticEvent: https://reactjs.org/docs/events.html
[27] Источник: https://habr.com/ru/post/443214/?utm_source=habrahabr&utm_medium=rss&utm_campaign=443214
Нажмите здесь для печати.