Skip to content
Topic 4 of 5
Theory

Формы и общее состояние

Управляемые поля

В обычном HTML поле ввода само хранит то, что в него напечатали. В React принято, чтобы значение поля хранилось в состоянии, а поле только показывало его. Такое поле называют управляемым (controlled):

function Search() {
  const [query, setQuery] = useState("");
  return (
    <>
      <input value={query} onChange={(e) => setQuery(e.target.value)} />
      <p>Ищем: {query}</p>
    </>
  );
}

Круг замыкается так: пользователь печатает → onChange → setQuery(новый текст) → React перерисовывает → поле показывает query. В React onChange срабатывает на каждый символ (как событие input в DOM).

Зачем так сложно? Значение всегда под рукой в переменной: его можно проверить, преобразовать (например, setQuery(e.target.value.toUpperCase())), очистить (setQuery("")) или показать в другом месте страницы.

Если написать value={...} без onChange, поле станет «только для чтения» — React будет возвращать ему значение из состояния, и печатать не получится.

Разные виды полей

<textarea value={text} onChange={(e) => setText(e.target.value)} />

<select value={city} onChange={(e) => setCity(e.target.value)}>
  <option value="msk">Москва</option>
  <option value="dyu">Душанбе</option>
</select>

<input type="checkbox" checked={agree} onChange={(e) => setAgree(e.target.checked)} />

У чекбокса вместо value — checked и e.target.checked.

Отправка формы

function Subscribe({ onSubscribe }) {
  const [email, setEmail] = useState("");

  const handleSubmit = (e) => {
    e.preventDefault();          // без перезагрузки страницы
    onSubscribe(email);
    setEmail("");                // очистить поле
  };

  return (
    <form onSubmit={handleSubmit}>
      <input value={email} onChange={(e) => setEmail(e.target.value)} />
      <button>Подписаться</button>
    </form>
  );
}

Кнопка внутри формы по умолчанию отправляет её, и сработает onSubmit — как по клику, так и по Enter.

Проверка без лишнего состояния

Можно ли отправить форму, не нужно хранить в отдельном useState — это вычисляется из того, что уже есть, прямо при отрисовке:

const valid = email.includes("@") && password.length >= 6;
<button disabled={!valid}>Войти</button>

Правило: если значение можно посчитать из props и состояния — считай, а не храни. Лишнее состояние легко «рассинхронизировать» с основным.

Подъём состояния

Иногда двум компонентам нужно одно и то же значение: фильтр и список, два поля конвертера, товар и корзина. Тогда состояние поднимают в их общего родителя, а детям передают значение и функцию для изменения через props:

function Filter({ value, onChange }) {
  return <input value={value} onChange={(e) => onChange(e.target.value)} />;
}

function List({ items, query }) {
  return (
    <ul>
      {items.filter((i) => i.includes(query)).map((i) => <li key={i}>{i}</li>)}
    </ul>
  );
}

function App() {
  const [query, setQuery] = useState("");          // состояние у общего родителя
  return (
    <>
      <Filter value={query} onChange={setQuery} />
      <List items={["кот", "кит", "пёс"]} query={query} />
    </>
  );
}

Данные в React текут сверху вниз (через props), а события — снизу вверх (через функции в props). У каждого значения один владелец — так приложение остаётся предсказуемым.

Итог

  • Управляемое поле: value={состояние} + onChange={(e) => set(e.target.value)}; чекбокс — checked.
  • Форма: onSubmit + e.preventDefault().
  • Что можно вычислить — вычисляй при отрисовке, а не храни в состоянии.
  • Общие данные — в общем родителе; детям — значение и функция-обработчик через props.

Живое приветствие

Easy+10 XP

Напиши компонент NameInput: поле <input> и под ним <p>. Поле управляемое (значение из состояния). В абзаце — Hello, имя!, где имя — введённый текст без пробелов по краям. Если поле пустое (или только пробелы) — Hello, stranger!.

""       → Hello, stranger!
" Ann "  → Hello, Ann!

Connect the connector to solve tasks

Task code runs on your own computer — faster and more reliable than in the browser. This needs the free CodeWithMe connector app. You only connect it once.

Looking for the connector on this computer…

  1. 1
    Download the connector for your system (Windows, macOS or Linux).Download the connectorOn the download page pick the file with your system in its name, e.g. windows-amd64.
  2. 2Run it and choose a folder for your solutions. It will install Python and Node.js there by itself when needed.
  3. 3
    Enter below the 6-digit code shown in the connector window (“Code for CodeWithMe”). If the browser asks about local network access — allow it.

The connector is open source (on GitHub), works only on your computer and runs code only after you enter the pairing code.