Solid.js, как и другие современные фреймворки для создания пользовательских интерфейсов, предоставляет мощные средства для работы с динамическими формами. Одной из ключевых особенностей Solid является его реактивность, которая делает управление состоянием форм и вложенных полей интуитивно понятным и эффективным. В этой статье рассматриваются способы работы с более сложными формами, которые включают вложенные поля и динамическое обновление данных.
Solid.js использует реактивность для отслеживания изменений в данных
формы. Каждый элемент формы может быть связан с отдельным состоянием с
помощью createSignal — функции, которая создает реактивное
состояние. Это состояние можно изменять и отслеживать, и оно
автоматически обновляет компоненты, связанные с этим состоянием.
Простой пример:
import { createSignal } from 'solid-js';
function SimpleForm() {
const [name, setName] = createSignal("");
const [email, setEmail] = createSignal("");
const handleSubmit = (e) => {
e.preventDefault();
console.log({ name: name(), email: email() });
};
return (
<form onSub mit={handleSubmit}>
<label>
Имя:
<input type="text" value={name()} onIn put={(e) => setName(e.target.value)} />
</label>
<label>
Email:
<input type="email" value={email()} onIn put={(e) => setEmail(e.target.value)} />
</label>
<button type="submit">Отправить</button>
</form>
);
}
Здесь createSignal используется для хранения значений
полей формы. Каждый раз, когда пользователь вводит текст, значения
обновляются через функции setName и setEmail.
Это демонстрирует базовое использование реактивности в контексте
форм.
Для более сложных форм, где данные вложены в несколько уровней (например, массивы или объекты), можно использовать несколько сигналов или объединить их в более сложные структуры. Вложенные поля требуют управления состоянием на нескольких уровнях, что Solid.js легко позволяет делать благодаря гибкости своих реактивных механизмов.
Рассмотрим пример формы для добавления адреса с несколькими вложенными полями:
import { createSignal } from 'solid-js';
function AddressForm() {
const [address, setAddress] = createSignal({
street: '',
city: '',
zip: ''
});
const handleInputChange = (field) => (e) => {
setAddress(prev => ({
...prev,
[field]: e.target.value
}));
};
const handleSubmit = (e) => {
e.preventDefault();
console.log(address());
};
return (
<form onSub mit={handleSubmit}>
<label>
Улица:
<input type="text" value={address().street} onIn put={handleInputChange('street')} />
</label>
<label>
Город:
<input type="text" value={address().city} onIn put={handleInputChange('city')} />
</label>
<label>
Почтовый индекс:
<input type="text" value={address().zip} onIn put={handleInputChange('zip')} />
</label>
<button type="submit">Отправить</button>
</form>
);
}
В этом примере состояние address — это объект с тремя
полями: street, city, и zip.
Каждый из этих элементов можно обновить отдельно с помощью функции
handleInputChange, которая обрабатывает изменения на разных
уровнях вложенности. Благодаря такому подходу можно управлять любыми
сложными структурами данных, обеспечивая поддержку реактивности на
каждом уровне.
Один из случаев, когда формы становятся особенно сложными, — это добавление или удаление полей в зависимости от действий пользователя. Например, форма может включать динамическое добавление нескольких адресов для одной заявки. Solid.js предоставляет простое и эффективное решение для таких случаев.
Пример с динамическим добавлением полей:
import { createSignal } from 'solid-js';
function DynamicAddressForm() {
const [addresses, setAddresses] = createSignal([{ street: '', city: '', zip: '' }]);
const handleInputChange = (index, field) => (e) => {
setAddresses(prev => {
const newAddresses = [...prev];
newAddresses[index] = { ...newAddresses[index], [field]: e.target.value };
return newAddresses;
});
};
const addAddress = () => {
setAddresses(prev => [...prev, { street: '', city: '', zip: '' }]);
};
const removeAddress = (index) => () => {
setAddresses(prev => prev.filter((_, i) => i !== index));
};
const handleSubmit = (e) => {
e.preventDefault();
console.log(addresses());
};
return (
<form onSub mit={handleSubmit}>
{addresses().map((address, index) => (
<div key={index}>
<label>
Улица:
<input type="text" value={address.street} onIn put={handleInputChange(index, 'street')} />
</label>
<label>
Город:
<input type="text" value={address.city} onIn put={handleInputChange(index, 'city')} />
</label>
<label>
Почтовый индекс:
<input type="text" value={address.zip} onIn put={handleInputChange(index, 'zip')} />
</label>
<button type="button" onCl ick={removeAddress(index)}>Удалить</button>
</div>
))}
<button type="button" onCl ick={addAddress}>Добавить адрес</button>
<button type="submit">Отправить</button>
</form>
);
}
Здесь создается форма, где можно динамически добавлять и удалять
блоки с адресами. Каждый новый адрес добавляется как новый объект в
массив addresses, и на каждый из них создается набор полей
для ввода. Для каждого поля и блока существует собственная реактивность,
и любые изменения автоматически обновляют соответствующие части
интерфейса.
Валидация данных в Solid.js осуществляется через добавление логики внутри обработчиков событий или реактивных функций. Для более сложных форм, включающих вложенные поля, валидация становится ключевым моментом.
Пример валидации для формы с вложенными полями:
import { createSignal } from 'solid-js';
function ValidatedForm() {
const [address, setAddress] = createSignal({ street: '', city: '', zip: '' });
const [errors, setErrors] = createSignal({});
const validate = () => {
const errors = {};
const addr = address();
if (!addr.street) errors.street = 'Улица обязательна';
if (!addr.city) errors.city = 'Город обязателен';
if (!addr.zip || !/^\d{5}$/.test(addr.zip)) errors.zip = 'Неверный почтовый индекс';
setErrors(errors);
return Object.keys(errors).length === 0;
};
const handleSubmit = (e) => {
e.preventDefault();
if (validate()) {
console.log(address());
}
};
const handleInputChange = (field) => (e) => {
setAddress(prev => ({ ...prev, [field]: e.target.value }));
};
return (
<form onSub mit={handleSubmit}>
<label>
Улица:
<input type="text" value={address().street} onIn put={handleInputChange('street')} />
{errors().street && <div>{errors().street}</div>}
</label>
<label>
Город:
<input type="text" value={address().city} onIn put={handleInputChange('city')} />
{errors().city && <div>{errors().city}</div>}
</label>
<label>
Почтовый индекс:
<input type="text" value={address().zip} onIn put={handleInputChange('zip')} />
{errors().zip && <div>{errors().zip}</div>}
</label>
<button type="submit">Отправить</button>
</form>
);
}
В этом примере добавлена простая валидация, которая проверяет, заполнены ли поля и соответствует ли почтовый индекс заданному формату. Ошибки отображаются непосредственно под каждым полем.
Solid.js предоставляет мощные инструменты для работы с формами, особенно когда требуется обрабатывать сложные структуры данных и вложенные поля. Его реактивная модель позволяет эффективно управлять состоянием формы, динамически добавлять и удалять поля, а также легко интегрировать валидацию. Вдобавок, гибкость и производительность Solid.js делают его отличным выбором для создания динамических, интерактивных интерфейсов.