В Preact управление состоянием компонентов осуществляется с помощью
хука useState. Для управления состоянием загрузки это
основной инструмент, позволяющий отслеживать процесс асинхронных
операций, таких как запросы к API. Создание состояния загрузки обычно
выглядит следующим образом:
import { h } from 'preact';
import { useState, useEffect } from 'preact/hooks';
function DataLoader() {
const [loading, setLoading] = useState(false);
const [data, setData] = useState(null);
const [error, setError] = useState(null);
return (
<div>
{loading && <p>Загрузка...</p>}
{error && <p>Ошибка: {error}</p>}
{data && <pre>{JSON.stringify(data, null, 2)}</pre>}
</div>
);
}
Здесь loading отражает текущее состояние компонента,
позволяя условно отображать индикатор загрузки.
Для выполнения асинхронных задач применяют хук
useEffect. Он позволяет запускать побочные эффекты, такие
как сетевые запросы, при монтировании компонента или изменении
зависимостей.
useEffect(() => {
setLoading(true);
fetch('https://api.example.com/data')
.then(response => response.json())
.then(result => setData(result))
.catch(err => setError(err.message))
.finally(() => setLoading(false));
}, []);
Ключевой момент: состояние loading должно изменяться в
начале асинхронного запроса и сбрасываться в блоке finally,
чтобы корректно отражать завершение операции независимо от
результата.
Для повторного использования логики загрузки часто применяют паттерн “Лоадер” — отдельный компонент, оборачивающий асинхронный вызов и предоставляющий универсальный интерфейс для отображения состояний:
function Loader({ promise, children }) {
const [loading, setLoading] = useState(true);
const [data, setData] = useState(null);
const [error, setError] = useState(null);
useEffect(() => {
promise
.then(result => setData(result))
.catch(err => setError(err.message))
.finally(() => setLoading(false));
}, [promise]);
if (loading) return <p>Загрузка...</p>;
if (error) return <p>Ошибка: {error}</p>;
return children(data);
}
Использование:
<Loader promise={fetch('https://api.example.com/data').then(res => res.json())}>
{data => <pre>{JSON.stringify(data, null, 2)}</pre>}
</Loader>
Такой подход отделяет логику загрузки от визуального представления, упрощает поддержку и повторное использование кода.
Если необходимо выполнять несколько параллельных запросов, состояние загрузки может быть представлено объектом или массивом. Пример с объектом:
function MultiLoader() {
const [loading, setLoading] = useState({ users: false, posts: false });
const [users, setUsers] = useState([]);
const [posts, setPosts] = useState([]);
useEffect(() => {
setLoading(prev => ({ ...prev, users: true }));
fetch('/api/users')
.then(res => res.json())
.then(setUsers)
.finally(() => setLoading(prev => ({ ...prev, users: false })));
setLoading(prev => ({ ...prev, posts: true }));
fetch('/api/posts')
.then(res => res.json())
.then(setPosts)
.finally(() => setLoading(prev => ({ ...prev, posts: false })));
}, []);
return (
<div>
{loading.users && <p>Загрузка пользователей...</p>}
{loading.posts && <p>Загрузка постов...</p>}
<pre>{JSON.stringify({ users, posts }, null, 2)}</pre>
</div>
);
}
Использование объекта позволяет гибко управлять состоянием нескольких независимых загрузок и точно отображать прогресс каждой из них.
Для минимизации лишних ререндеров при изменении состояния загрузки
важно обновлять только необходимые части состояния. Например, при работе
с объектом состояния следует использовать функциональный вариант
setState:
setLoading(prev => ({ ...prev, users: false }));
Это гарантирует, что изменения будут объединяться, а не перезаписывать весь объект.
Для больших данных или медленных соединений полезно отображать
прогресс. В Preact можно реализовать это с помощью дополнительного
состояния progress:
const [progress, setProgress] = useState(0);
useEffect(() => {
const xhr = new XMLHttpRequest();
xhr.open('GET', '/large-file');
xhr.onprogr ess = event => {
if (event.lengthComputable) {
setProgress(Math.round((event.loaded / event.total) * 100));
}
};
xhr.onl oad = () => setProgress(100);
xhr.send();
}, []);
Интерфейс может включать прогресс-бар или процент загрузки, что улучшает пользовательский опыт.
Эффективное управление состоянием загрузки в Preact строится на
комбинации useState, useEffect и аккуратного
разделения логики и представления. Паттерн “Лоадер”, объекты состояния
для параллельных загрузок и прогресс-индикация создают надежную
архитектуру для асинхронных операций и делают код предсказуемым и легко
поддерживаемым.