Формы¶
В React HTML-элементы формы ведут себя несколько отлично от остальных DOM-элементов, так как у элементов формы изначально есть внутреннее состояние. К примеру, в эту HTML-форму можно ввести имя:
1 2 3 4 5 6 7 | |
По умолчанию браузер переходит на другую страницу при отправке HTML-форм, в том числе и этой. Если вас это устраивает, то не надо ничего менять, в React формы работают как обычно. Однако, чаще всего форму удобнее обрабатывать с помощью JavaScript-функции, у которой есть доступ к введённым данным. Стандартный способ реализации такого поведения называется «управляемые компоненты».
Управляемые компоненты¶
В HTML элементы формы, такие как <input>, <textarea> и <select>, обычно сами управляют своим состоянием и обновляют его когда пользователь вводит данные. В React мутабельное состояние обычно содержится в свойстве компонентов state и обновляется только через вызов setState().
Мы можем скомбинировать оба подхода и сделать состояние React-компонента "единственным источником правды". Тогда React-компонент будет рендерить форму и контролировать её поведение в ответ на пользовательский ввод. Значение элемента формы input в этом случае будет контролировать React, а сам элемент будет называться управляемый компонент».
Допустим, мы хотим, чтобы предыдущий пример выводил в консоль имя, когда мы отправляем форму. Тогда можно написать форму в виде управляемого компонента:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 | |
Мы установили атрибут value для поля ввода, и теперь в нём всегда будет отображаться значение this.state.value. Состояние React-компонента стало «источником истины». А так как каждое нажатие клавиши вызывает handleChange, который обновляет состояние React-компонента, значение в поле будет обновляться по мере того, как пользователь печатает.
В управляемом компоненте с каждой мутацией состояния связана функция-обработчик. Благодаря этому валидация или изменение введённого значения становится простой задачей. Например, если мы хотим, чтобы имя обязательно было набрано заглавными буквами, можно написать такой handleChange:
1 2 3 | |
Тег textarea¶
HTML-элемент <textarea> в качестве текста отображает дочерний элемент:
1 2 3 | |
В React <textarea> использует атрибут value. Таким образом, форму с <textarea> можно написать почти тем же способом, что и форму с однострочным <input>:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 | |
Обратите внимание, что мы инициализировали this.state.value в конструкторе, так что в текстовой области изначально есть текст.
Тег select¶
В HTML <select> создаёт выпадающий список. HTML-код в этом примере создаёт выпадающий список вкусов:
1 2 3 4 5 6 | |
Пункт списка «Кокос» выбран по умолчанию из-за установленного атрибута selected. React вместо этого атрибута использует value в корневом теге select. В управляемом компоненте так удобнее, потому что обновлять значение нужно только в одном месте (state). Пример:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 | |
Подводя итог, <input type="text">, <textarea>, и <select> работают очень похоже. Все они принимают атрибут value, который можно использовать, чтобы реализовать управляемый компонент.
Примечание
В атрибут
valueможно передать массив, что позволит выбрать несколько опций в тегеselect:
1<select multiple={true} value={['Б', 'В']}>
Загрузка файла¶
В HTML <input type="file"> позволяет пользователю выбрать один или несколько файлов для загрузки с устройства на сервер или управлять им через JavaScript с помощью File API.
1 | |
Так как значение такого элемента доступно только для чтения, это неуправляемый React-компонент. Мы расскажем про этот и другие неуправляемые компоненты далее в документации.
Обработка нескольких элементов input¶
Если вам нужны несколько управляемых элементов input, вы можете назначить каждому из них атрибут name, что позволит функции-обработчику решать, что делать, основываясь на значении event.target.name.
Пример:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 | |
Обратите внимание, что мы используем вычисляемые имена свойств, чтобы обновить значение в state через ключ, который соответствует атрибуту name элемента input:
1 2 3 | |
Идентичный ES5-код:
1 2 3 | |
Кроме того, setState() автоматически производит слияние части состояния с текущим состоянием, то есть нам нужно передать в него только ту часть state, которую хотим изменить.
Значение null управляемого компонента¶
Если установить управляемому компоненту проп value, то пользователь не сможет изменить его значение без вашего желания. Если вы установили value, а поле ввода по-прежнему можно редактировать, то, возможно, вы случайно задали value, равный undefined или null.
Код ниже это демонстрирует. (Изначально заблокированный input становится редактируемым после небольшой задержки.)
1 2 3 4 5 | |
Альтернативы управляемым компонентам¶
Использование управляемых компонентов иногда может быть утомительным. Приходится писать обработчик события для каждого варианта изменения ваших данных и проводить всё состояние формы через компонент React. Это может особенно раздражать, если вы переносите существующую кодовую базу в React, или когда работаете над интеграцией React-приложения с другой библиотекой. В такой ситуации могут пригодиться неуправляемые компоненты — альтернативная техника реализации ввода данных в форму.
Полноценные решения¶
Если вы ищите полноценное решение, которое может валидировать ввод, запомнить посещённые поля формы и обработать её отправку, присмотритесь к Formik. Эта библиотека построена на принципах управляемых компонентов и управления состоянием, так что не пренебрегайте их изучением.