Haunted — это библиотека для создания веб-компонентов с
использованием реактивного подхода, вдохновлённого функциональными
компонентами React. Валидация форм в Haunted строится на реактивных
сигналах и управлении состоянием компонентов через useState
и useEffect, что позволяет эффективно отслеживать изменения
данных и динамически обновлять интерфейс.
Форма в Haunted обычно представлена реактивным объектом состояния, который хранит значения полей и информацию о корректности данных:
import { html, component } from 'haunted';
import { useState, useEffect } from 'haunted';
function FormComponent() {
const [formData, setFormData] = useState({
username: '',
email: '',
password: ''
});
const [errors, setErrors] = useState({});
return html`
<form @submit=${handleSubmit}>
<input
type="text"
name="username"
.value=${formData.username}
@input=${e => setFormData({...formData, username: e.target.value})}
/>
${errors.username ? html`<span>${errors.username}</span>` : ''}
<input
type="email"
name="email"
.value=${formData.email}
@input=${e => setFormData({...formData, email: e.target.value})}
/>
${errors.email ? html`<span>${errors.email}</span>` : ''}
<input
type="password"
name="password"
.value=${formData.password}
@input=${e => setFormData({...formData, password: e.target.value})}
/>
${errors.password ? html`<span>${errors.password}</span>` : ''}
<button type="submit">Отправить</button>
</form>
`;
function handleSubmit(e) {
e.preventDefault();
const validationErrors = validate(formData);
setErrors(validationErrors);
if (Object.keys(validationErrors).length === 0) {
console.log('Форма корректна', formData);
}
}
}
customElements.define('form-component', component(FormComponent));
В этом примере состояние formData содержит значения
полей, а errors хранит ошибки валидации. Реактивность
Haunted позволяет автоматически перерисовывать интерфейс при изменении
этих объектов.
Валидация реализуется отдельной функцией, которая возвращает объект с ошибками:
function validate(data) {
const errors = {};
if (!data.username.trim()) {
errors.username = 'Имя пользователя обязательно';
} else if (data.username.length < 3) {
errors.username = 'Имя пользователя должно быть не менее 3 символов';
}
if (!data.email.trim()) {
errors.email = 'Email обязателен';
} else if (!/^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(data.email)) {
errors.email = 'Неверный формат email';
}
if (!data.password) {
errors.password = 'Пароль обязателен';
} else if (data.password.length < 6) {
errors.password = 'Пароль должен быть не менее 6 символов';
}
return errors;
}
Такой подход отделяет бизнес-логику проверки от интерфейса, что упрощает тестирование и поддержку кода.
Haunted позволяет реагировать на изменения данных в реальном времени
с помощью useEffect. Например, можно автоматически
проверять поле при изменении значения:
useEffect(() => {
setErrors(prevErrors => {
const newErrors = {...prevErrors};
if (formData.username && formData.username.length >= 3) {
delete newErrors.username;
}
return newErrors;
});
}, [formData.username]);
Подобная реактивная проверка позволяет пользователю видеть ошибки сразу, не дожидаясь отправки формы.
Для сложных форм удобно создавать отдельные валидаторы для каждого поля:
const validators = {
username: value => value.length >= 3 ? null : 'Имя слишком короткое',
email: value => /^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(value) ? null : 'Неверный формат email',
password: value => value.length >= 6 ? null : 'Пароль слишком короткий'
};
function validateField(name, value) {
return validators[name] ? validators[name](value) : null;
}
function handleInputChange(e) {
const { name, value } = e.target;
setFormData({...formData, [name]: value});
setErrors({...errors, [name]: validateField(name, value)});
}
Такой подход упрощает добавление новых полей и изменяемых правил валидации без переписывания основной логики.
Даже при динамической проверке важно проводить финальную проверку при сабмите формы:
function handleSubmit(e) {
e.preventDefault();
const newErrors = Object.fromEntries(
Object.entries(formData).map(([key, value]) => [key, validateField(key, value)]).filter(([_, v]) => v)
);
setErrors(newErrors);
if (!Object.keys(newErrors).length) {
// отправка данных на сервер
}
}
Использование реактивных сигналов Haunted вместе с функциями проверки позволяет минимизировать дублирование кода и гарантировать консистентность состояния формы.
Форма может содержать вложенные объекты, массивы элементов или
динамически создаваемые поля. Haunted позволяет управлять такими
структурами через useState и обновление по ссылке:
const [addresses, setAddresses] = useState([{ street: '', city: '' }]);
function addAddress() {
setAddresses([...addresses, { street: '', city: '' }]);
}
function updateAddress(index, field, value) {
const updated = addresses.map((addr, i) => i === index ? {...addr, [field]: value} : addr);
setAddresses(updated);
}
Валидация массивов и вложенных объектов реализуется аналогично: перебор элементов с применением валидаторов к каждому полю.
Haunted прекрасно работает с кастомными элементами
<my-input> или сторонними компонентами. Для этого
достаточно привязывать события @input и значения через
.value или свойства, что позволяет строить гибкие формы с
полной реактивностью.
Эти подходы делают Haunted удобным инструментом для построения сложных форм с полной поддержкой реактивной валидации, мгновенной обратной связью и управляемым состоянием.