Работа с формами
В React HTML-элементы формы ведут себя немного иначе по сравнению с DOM-элементами, так как у элементов формы изначально есть внутреннее состояние. К примеру, в эту HTML-форму можно ввести имя:
1.Работа с формами
<form>
<label>
Имя:
<input type="text" name="name" />
</label>
<input type="submit" value="Отправить" />
</form>
По умолчанию браузер переходит на другую страницу при отправке HTML-форм, в том числе и этой. Если вас это устраивает, то не надо ничего менять, в React формы работают как обычно. Однако чаще всего форму удобнее обрабатывать с помощью JavaScript-функции, у которой есть доступ к введённым данным. Стандартный способ реализации такого поведения называется «управляемые компоненты».
Управляемые компоненты
В HTML элементы формы, такие как <input>
, <textarea>
и <select>
, обычно сами управляют своим состоянием и обновляют его когда пользователь вводит данные. В React мутабельное состояние обычно содержится в свойстве компонентов state
и обновляется только через вызов setState()
Мы можем скомбинировать оба подхода и сделать состояние React-компонента «единственным источником правды». Тогда React-компонент будет рендерить форму и контролировать её поведение в ответ на пользовательский ввод. Значение элемента формы input в этом случае будет контролировать React, а сам элемент будет называться «управляемый компонент».
Допустим, мы хотим, чтобы предыдущий пример показал в модальном окне введённое имя, когда мы отправляем форму. Тогда можно написать форму в виде управляемого компонента:
import React, { useState } from 'react';
function NameForm() {
const [value, setValue] = useState('');
const handleChange = (event) => {
setValue(event.target.value);
};
const handleSubmit = (event) => {
alert('Отправленное имя: ' + value);
event.preventDefault();
};
return (
<form onSubmit={handleSubmit}>
<label>
Имя:
<input type="text" value={value} onChange={handleChange} />
</label>
<input type="submit" value="Отправить" />
</form>
);
}
export default NameForm;
Мы установили атрибут value
для поля ввода и теперь в нём всегда будет отображаться значение this.state.value
. Состояние React-компонента стало «источником истины». А так как каждое нажатие клавиши вызывает handleChange
, который обновляет состояние React-компонента, значение в поле будет обновляться по мере того, как пользователь печатает.
В управляемом компоненте значение поля ввода всегда определяется состоянием React. Хотя это означает, что вы должны написать немного больше кода, теперь вы сможете передать значение и другим UI-элементам или сбросить его с других обработчиков событий.
Тег textarea
HTML-элемент <textarea>
в качестве текста отображает дочерний элемент:
<textarea>
Привет! Тут просто немного текста внутри тега textarea
</textarea>
В React <textarea>
использует атрибут value
. Таким образом, форму с <textarea>
можно написать почти тем же способом, что и форму с однострочным <input>
:
import React, { useState } from 'react';
function EssayForm() {
const [value, setValue] = useState('Будьте любезны, напишите сочинение о вашем любимом DOM-элементе.');
const handleChange = (event) => {
setValue(event.target.value);
};
const handleSubmit = (event) => {
alert('Сочинение отправлено: ' + value);
event.preventDefault();
};
return (
<form onSubmit={handleSubmit}>
<label>
Сочинение:
<textarea value={value} onChange={handleChange} />
</label>
<input type="submit" value="Отправить" />
</form>
);
}
export default EssayForm;
Обратите внимание, что мы инициализировали this.state.value
в конструкторе, так что в текстовой области изначально есть текст.
Тег select
В HTML <select>
создаёт выпадающий список. HTML-код в этом примере создаёт выпадающий список вкусов:
<select>
<option value="grapefruit">Грейпфрут</option>
<option value="lime">Лайм</option>
<option selected value="coconut">Кокос</option>
<option value="mango">Манго</option>
</select>
Пункт списка «Кокос» выбран по умолчанию из-за установленного атрибута selected
. React вместо этого атрибута использует value
в корневом теге select
. В управляемом компоненте так удобнее, потому что обновлять значение нужно только в одном месте (state
). Пример:
import React, { useState } from 'react';
function FlavorForm() {
const [value, setValue] = useState('coconut');
const handleChange = (event) => {
setValue(event.target.value);
};
const handleSubmit = (event) => {
alert('Ваш любимый вкус: ' + value);
event.preventDefault();
};
return (
<form onSubmit={handleSubmit}>
<label>
Выберите ваш любимый вкус:
<select value={value} onChange={handleChange}>
<option value="grapefruit">Грейпфрут</option>
<option value="lime">Лайм</option>
<option value="coconut">Кокос</option>
<option value="mango">Манго</option>
</select>
</label>
<input type="submit" value="Отправить" />
</form>
);
}
export default FlavorForm;
Подводя итог, <input type="text">
, <textarea>
, и <select>
работают очень похоже. Все они принимают атрибут value
, который можно использовать, чтобы реализовать управляемый компонент.
Примечание
В атрибут
value
можно передать массив, что позволит выбрать несколько опций в тегеselect
:<select multiple={true} value={['Б', 'В']}>
Загрузка файла
В HTML <input type="file">
позволяет пользователю выбрать один или несколько файлов для загрузки с устройства на сервер или управлять им через JavaScript с помощью File API.
<input type="file" />
Так как значение такого элемента доступно только для чтения, это неуправляемый React-компонент.
Обработка нескольких элементов input
Если вам нужны несколько управляемых элементов input
, вы можете назначить каждому из них атрибут name
, что позволит функции-обработчику решать, что делать, основываясь на значении event.target.name
.
Пример:
import React, { useState } from 'react';
function Reservation() {
const [formState, setFormState] = useState({
isGoing: true,
numberOfGuests: 2,
});
const handleInputChange = (event) => {
const target = event.target;
const value = target.type === 'checkbox' ? target.checked : target.value;
const name = target.name;
setFormState({
...formState,
[name]: value,
});
};
return (
<form>
<label>
Пойдут:
<input
name="isGoing"
type="checkbox"
checked={formState.isGoing}
onChange={handleInputChange}
/>
</label>
<br />
<label>
Количество гостей:
<input
name="numberOfGuests"
type="number"
value={formState.numberOfGuests}
onChange={handleInputChange}
/>
</label>
</form>
);
}
export default Reservation;
2. Условный рендеринг
В React не существует специального синтаксиса для описания условий, вместо этого можно использовать обычный код на JavaScript. Например, для условного рендеринга JSX-кода можно применять if
:
let content;
if (isLoggedIn) {
content = <AdminPanel />;
} else {
content = <LoginForm />;
}
return (
<div>
{content}
</div>
);
Если вы предпочитаете писать более компактный код, используйте условный оператор ?
. В отличие от if
его можно использовать в JSX:
<div>
{isLoggedIn ? (
<AdminPanel />
) : (
<LoginForm />
)}
</div>
Когда вам не нужна ветка else
, можно использовать более короткий логический оператор &&
:
<div>
{isLoggedIn && <AdminPanel />}
</div>
Все эти способы подходят и для задания условий в атрибутах. Если вам не знакомы такие синтаксические конструкции JavaScript, вы можете начать с использования if...else
.
3. Рендеринг списков
Для отрисовки списков компонентов вам будет нужно использовать такие возможности JavaScript, как цикл for
и функция массива map()
.
Например, представим, что у вас есть массив продуктов:
const products = [
{ title: 'Капуста', id: 1 },
{ title: 'Чеснок', id: 2 },
{ title: 'Яблоко', id: 3 },
];
Преобразуйте этот массив в массив элементов <li>
с помощью функции map()
внутри вашего компонента:
const listItems = products.map(product =>
<li key={product.id}>
{product.title}
</li>
);
return (
<ul>{listItems}</ul>
);

Обратите внимание, что у <li>
есть атрибут key
. Для каждого элемента списка вам нужно задавать ключ в виде строки или числа, который позволит однозначно отделить этот элемент от остальных в списке. Обычно этот ключ берется из ваших данных, например, это может быть идентификатор из базы данных. React использует эти ключи при добавлении, удалении или изменении порядка элементов.
Last updated