Обработка отправки

Haunted — это легковесная библиотека для создания веб-компонентов на основе хуков, вдохновлённая React. Одной из ключевых задач при работе с веб-компонентами является обработка событий формы, в частности отправки данных. В Haunted обработка отправки строится на стандартных DOM-событиях, но с использованием хуков для управления состоянием и побочными эффектами.


Использование события submit

Форма в Haunted создаётся как обычный HTML-элемент <form>. Для перехвата отправки используется событие submit, которое можно обрабатывать с помощью колбэка, передаваемого через атрибут элемента.

Пример базовой формы:

import { html, component } from 'haunted';
import { useState } from 'haunted';

function MyForm() {
  const [name, setName] = useState('');
  const [submitted, setSubmitted] = useState(false);

  const handleSubmit = (event) => {
    event.preventDefault(); // предотвращает стандартную перезагрузку страницы
    setSubmitted(true);
    console.log('Отправлено имя:', name);
  };

  return html`
    <form @submit=${handleSubmit}>
      <label>
        Имя:
        <input type="text" .value=${name} @input=${e => setName(e.target.value)} />
      </label>
      <button type="submit">Отправить</button>
      ${submitted ? html`<p>Форма отправлена!</p>` : ''}
    </form>
  `;
}

customElements.define('my-form', component(MyForm));

Ключевые моменты:

  • @submit=${handleSubmit} привязывает обработчик события submit к форме.
  • event.preventDefault() предотвращает стандартное поведение браузера.
  • Состояние управляется через useState, что позволяет обновлять UI при отправке формы.

Передача данных и управление состоянием

Haunted позволяет легко интегрировать формы с внутренним состоянием компонента. Каждый <input> связывается с состоянием с помощью двусторонней привязки через .value и обработчик @input. Это обеспечивает синхронизацию данных без необходимости обращаться напрямую к DOM.

Пример с несколькими полями:

function RegistrationForm() {
  const [formData, setFormData] = useState({ email: '', password: '' });
  const [submitted, setSubmitted] = useState(false);

  const handleChange = (field) => (e) => {
    setFormData({ ...formData, [field]: e.target.value });
  };

  const handleSubmit = (event) => {
    event.preventDefault();
    console.log('Данные формы:', formData);
    setSubmitted(true);
  };

  return html`
    <form @submit=${handleSubmit}>
      <label>
        Email:
        <input type="email" .value=${formData.email} @input=${handleChange('email')} />
      </label>
      <label>
        Пароль:
        <input type="password" .value=${formData.password} @input=${handleChange('password')} />
      </label>
      <button type="submit">Зарегистрироваться</button>
      ${submitted ? html`<p>Регистрация завершена!</p>` : ''}
    </form>
  `;
}

customElements.define('registration-form', component(RegistrationForm));

Особенности:

  • Использование объекта formData позволяет централизованно хранить значения всех полей формы.
  • Функция handleChange создаёт замыкание для конкретного поля, что упрощает обработку множества инпутов.
  • При изменении любого поля компонент автоматически перерисовывается благодаря реактивности useState.

Асинхронная обработка отправки

Часто формы требуют отправки данных на сервер. Haunted легко интегрируется с асинхронными функциями, не блокируя интерфейс.

Пример с асинхронным запросом:

function AsyncForm() {
  const [email, setEmail] = useState('');
  const [status, setStatus] = useState('idle');

  const handleSubmit = async (event) => {
    event.preventDefault();
    setStatus('loading');

    try {
      const response = await fetch('https://example.com/api/subscribe', {
        method: 'POST',
        headers: { 'Content-Type': 'application/json' },
        body: JSON.stringify({ email }),
      });

      if (!response.ok) throw new Error('Ошибка сети');

      setStatus('success');
    } catch (error) {
      console.error(error);
      setStatus('error');
    }
  };

  return html`
    <form @submit=${handleSubmit}>
      <label>
        Email:
        <input type="email" .value=${email} @input=${e => setEmail(e.target.value)} />
      </label>
      <button type="submit">Подписаться</button>
      ${status === 'loading' ? html`<p>Отправка...</p>` : ''}
      ${status === 'success' ? html`<p>Успешно отправлено!</p>` : ''}
      ${status === 'error' ? html`<p>Ошибка при отправке</p>` : ''}
    </form>
  `;
}

customElements.define('async-form', component(AsyncForm));

Преимущества подхода:

  • Состояние status управляет визуальной обратной связью.
  • Использование async/await упрощает чтение кода и обработку ошибок.
  • Haunted автоматически перерисовывает компонент при изменении состояния.

Валидация формы

Валидация может выполняться как на уровне браузера (через атрибуты required, pattern), так и программно. Программная валидация часто интегрируется в обработчик submit:

const handleSubmit = (event) => {
  event.preventDefault();
  if (!email.includes('@')) {
    setStatus('invalid');
    return;
  }
  setStatus('success');
};

Для сложных форм удобно использовать отдельные функции проверки каждого поля, сохраняя результат в состоянии.


Итоговые рекомендации

  • Использовать @submit для перехвата отправки форм.
  • Управлять состоянием полей через useState.
  • Обеспечивать асинхронную обработку с async/await и отображать состояние отправки.
  • Применять программную и встроенную в браузер валидацию.
  • Держать UI реактивным: каждое изменение состояния должно автоматически отражаться в интерфейсе.

Haunted делает работу с формами модульной, реактивной и удобной для масштабирования сложных веб-компонентов.