🟨 React
Легко
🕐 1 story point

React: Управляемая форма и отправка

Соберите управляемую форму с несколькими полями и чекбоксом. При отправке покажите собранные данные и очистите форму.

Александр, тимлид стажировки React

Бизнес-кейс. LeadCapture — мини-форма лида: имя, email, сообщение и согласие на рассылку.

Что сделать

  • Сделайте все поля управляемыми: значения из состояния, обновление через onChange.
  • Кнопка «Отправить» активна только когда заполнены имя и email.
  • В onSubmit соберите объект данных и отобразите его ниже.
  • После отправки сбросьте поля формы.

Как выглядит

Карточка с полями формы, чекбоксом, кнопкой отправки и блоком «Отправлено». Превью: UI формы

💡 Подсказка
  • Состояния: const [name, setName] = useState('') и аналогично для остальных.
  • Кнопка: disabled={!name.trim() || !email.trim()}.
  • onSubmit: e.preventDefault(); собрать { name, email, message, subscribe }, показать, затем очистить поля.
  • Вынесите canSubmit в переменную для читабельности.
👀 Решение
import React, { useState } from 'react';
import './styles.css';
 
export function FeedbackForm() {
  const [name, setName] = useState('');
  const [email, setEmail] = useState('');
  const [message, setMessage] = useState('');
  const [subscribe, setSubscribe] = useState(false);
  const [submitted, setSubmitted] = useState(null);
 
  function handleSubmit(e) {
    e.preventDefault();
    const canSubmit = name.trim() && email.trim();
    if (!canSubmit) return;
    setSubmitted({ name, email, message, subscribe });
    setName('');
    setEmail('');
    setMessage('');
    setSubscribe(false);
  }
 
  const canSubmit = name.trim() && email.trim();
 
  return (
    <article className="card" data-testid="form-card">
      <header>
        <h2 className="title">LeadCapture: форма обратной связи</h2>
        <p className="subtitle">Управляемые поля + чекбокс, отправка формы</p>
      </header>
 
      <form className="row" onSubmit={handleSubmit} aria-label="form">
        <input
          className="input"
          type="text"
          placeholder="Имя"
          value={name}
          onChange={(e) => setName(e.target.value)}
          aria-label="name"
        />
        <input
          className="input"
          type="email"
          placeholder="Email"
          value={email}
          onChange={(e) => setEmail(e.target.value)}
          aria-label="email"
        />
        <textarea
          className="textarea"
          placeholder="Сообщение"
          value={message}
          onChange={(e) => setMessage(e.target.value)}
          aria-label="message"
          rows={3}
        />
        <label className="checkbox-row">
          <input
            className="checkbox"
            type="checkbox"
            checked={subscribe}
            onChange={(e) => setSubscribe(e.target.checked)}
            aria-label="subscribe"
          />
          <span>Подписаться на новости</span>
        </label>
        <div className="actions">
          <button className="button" type="submit" disabled={!canSubmit}>Отправить</button>
        </div>
      </form>
 
      {submitted && (
        <section className="result" aria-label="result">
          <p><strong>Отправлено:</strong></p>
          <p>Имя: {submitted.name}</p>
          <p>Email: {submitted.email}</p>
          <p>Сообщение: {submitted.message}</p>
          <p>Подписка: {submitted.subscribe ? 'Да' : 'Нет'}</p>
        </section>
      )}
    </article>
  );
}
 
export default function App() {
  return (
    <main className="challenge-container">
      <section>
        <FeedbackForm />
      </section>
    </main>
  );
}

🧑‍💻 Это не баг! Это фича!

Редактор кода намеренно скрыт на мобильном.

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

📖 Сейчас: Изучи задачу, продумай решение. Действуй как стратег.

💻 Потом: Сядь за компьютер, открой сайт и реализуй все идеи с комфортом. Действуй как код-джедай!