Haunted — это библиотека для создания веб-компонентов с использованием реактивного подхода на базе Hooks, аналогично React, но с упором на нативные веб-компоненты. Управление состоянием загрузки является одной из ключевых задач при работе с асинхронными данными и пользовательским интерфейсом.
Состояние загрузки обычно представляется булевым флагом, который
показывает, выполняется ли в данный момент асинхронная операция. В
Haunted это состояние удобно хранить с помощью хука
useState.
import { html, component, useState, useEffect } from 'haunted';
function DataLoader() {
const [data, setData] = useState(null);
const [loading, setLoading] = useState(true);
const [error, setError] = useState(null);
useEffect(() => {
fetch('https://api.example.com/data')
.then(response => response.json())
.then(json => {
setData(json);
setLoading(false);
})
.catch(err => {
setError(err);
setLoading(false);
});
}, []);
if (loading) return html`<p>Загрузка...</p>`;
if (error) return html`<p>Ошибка: ${error.message}</p>`;
return html`<pre>${JSON.stringify(data, null, 2)}</pre>`;
}
customElements.define('data-loader', component(DataLoader));
Ключевые моменты:
loading определяет момент отображения индикатора
загрузки.useEffect обеспечивает запуск
асинхронного запроса только один раз при монтировании компонента.Для улучшения UX состояние загрузки часто сопровождается анимацией или скелетонами (skeleton screens). В Haunted можно динамически менять разметку в зависимости от состояния:
function SkeletonLoader() {
const [loading, setLoading] = useState(true);
useEffect(() => {
const timer = setTimeout(() => setLoading(false), 3000);
return () => clearTimeout(timer);
}, []);
return html`
${loading
? html`<div class="skeleton">Загрузка контента...</div>`
: html`<div>Контент загружен</div>`}
`;
}
customElements.define('skeleton-loader', component(SkeletonLoader));
Особенности:
html и полностью
реактивен.Иногда требуется использовать асинхронные функции напрямую в хуках. В
Haunted нельзя передавать асинхронную функцию в useEffect
напрямую, но можно создать вложенную функцию:
useEffect(() => {
async function fetchData() {
try {
setLoading(true);
const response = await fetch('https://api.example.com/data');
const result = await response.json();
setData(result);
} catch (err) {
setError(err);
} finally {
setLoading(false);
}
}
fetchData();
}, []);
Преимущества такого подхода:
try/catch.loading и
error.В сложных приложениях состояния загрузки могут сочетаться с другими
реактивными состояниями: фильтрацией, пагинацией, обновлением данных.
Для этого используется комбинация нескольких useState и
условная логика в шаблоне:
function PaginatedLoader({ page }) {
const [data, setData] = useState([]);
const [loading, setLoading] = useState(true);
useEffect(() => {
setLoading(true);
fetch(`https://api.example.com/data?page=${page}`)
.then(res => res.json())
.then(json => setData(json))
.finally(() => setLoading(false));
}, [page]);
return html`
${loading
? html`<p>Загрузка страницы ${page}...</p>`
: html`<ul>${data.map(item => html`<li>${item.name}</li>`)}</ul>`}
`;
}
customElements.define('paginated-loader', component(PaginatedLoader));
Здесь ключевой момент: состояние загрузки привязано к параметру
page. Haunted автоматически перерендеривает компонент при
изменении зависимостей хука useEffect.
error облегчает отладку и отображение пользовательских
сообщений.Состояния загрузки в Haunted создают плавный пользовательский опыт и позволяют контролировать асинхронные процессы в реактивной модели веб-компонентов, обеспечивая полную управляемость визуального состояния интерфейса.