Fresh — современный фреймворк для разработки веб-приложений с акцентом на быстрый рендеринг и минимальное использование клиентского JavaScript. Одной из ключевых особенностей является концепция островов интерактивности (islands of interactivity), когда большая часть страницы рендерится на сервере, а интерактивные компоненты загружаются и инициализируются только при необходимости. Формы в таких островах требуют особого подхода.
В Fresh формы могут существовать в основном на сервере. HTML-форма
создаётся с использованием стандартного <form> и
управляется серверными обработчиками (handlers) через API
роуты. Такой подход обеспечивает:
Минимальную загрузку JavaScript Большинство форм остаются статичными до момента взаимодействия пользователя.
Повышенную безопасность Обработка данных происходит на сервере, что снижает риск уязвимостей XSS и CSRF.
Пример простой формы регистрации на сервере:
/** @jsx h */
import { h } from "preact";
export default function SignupForm() {
return (
<form method="POST" action="/signup">
<label>
Имя:
<input type="text" name="name" required />
</label>
<label>
Email:
<input type="email" name="email" required />
</label>
<button type="submit">Зарегистрироваться</button>
</form>
);
}
На сервере обрабатывается POST-запрос через роут
/signup, который получает данные, валидирует их и
сохраняет.
Интерактивные формы требуют клиентской логики: динамическая валидация, автозаполнение, реакция на события без перезагрузки страницы. Fresh позволяет превратить отдельные компоненты форм в острова, которые загружаются по необходимости.
Пример использования интерактивного острова:
/** @jsx h */
import { h } from "preact";
import { useState } from "preact/hooks";
export default function InteractiveForm() {
const [email, setEmail] = useState("");
const [error, setError] = useState("");
const handleSubmit = async (e) => {
e.preventDefault();
if (!email.includes("@")) {
setError("Некорректный email");
return;
}
setError("");
const response = await fetch("/subscribe", {
method: "POST",
body: JSON.stringify({ email }),
headers: { "Content-Type": "application/json" },
});
if (!response.ok) setError("Ошибка сервера");
};
return (
<form onSub mit={handleSubmit}>
<input
type="email"
value={email}
onIn put={(e) => setEmail(e.target.value)}
placeholder="Email"
/>
<button type="submit">Подписаться</button>
{error && <p>{error}</p>}
</form>
);
}
Ключевые особенности интерактивного острова:
Важным аспектом является совместная работа серверной и клиентской логики. Fresh позволяет:
Паттерн «сервер + остров» гарантирует:
Ошибки формы могут быть обработаны:
Пример комбинированной валидации:
// Серверная часть
export async function POST(req) {
const data = await req.json();
if (!data.email.includes("@")) {
return Response.json({ error: "Неверный email" }, { status: 400 });
}
// Сохранение данных
return Response.json({ success: true });
}
// Клиентский остров
const handleSubmit = async (e) => {
e.preventDefault();
const response = await fetch("/subscribe", {
method: "POST",
body: JSON.stringify({ email }),
headers: { "Content-Type": "application/json" },
});
const result = await response.json();
if (result.error) setError(result.error);
};
Таким образом, сервер проверяет корректность и безопасность, а клиент — удобство и мгновенную реакцию.
Острова позволяют добавлять или удалять поля формы на лету, изменять состояния в зависимости от ввода пользователя:
const [fields, setFields] = useState([{ name: "" }]);
const addField = () => setFields([...fields, { name: "" }]);
HTML рендерится через map, а новые поля управляются
состоянием острова. Такой подход недоступен для чисто серверных форм без
JavaScript.
Использование островов улучшает UX:
fetch
предотвращает перезагрузку страницы.Фреймворк Fresh с островами интерактивности позволяет создавать быстрые, безопасные и удобные формы, сочетая преимущества серверного рендера и локальной клиентской логики.