Состояния loading и error

Atomico — это современная библиотека для создания веб-компонентов с реактивными состояниями. Одной из ключевых задач при построении интерактивных компонентов является корректная обработка асинхронных операций, таких как загрузка данных или выполнение сетевых запросов. Для этого используются состояния loading и error, которые позволяют отслеживать прогресс выполнения операций и реагировать на ошибки.


Состояние loading

Состояние loading отражает, что в данный момент выполняется асинхронная операция. В Atomico для этого обычно применяется реактивная переменная, создаваемая с помощью функции useState.

Пример создания состояния loading:

import { c, useState, html } from "atomico";

function DataFetcher() {
    const [loading, setLoading] = useState(false);
    const [data, setData] = useState(null);

    async function fetchData() {
        setLoading(true);
        try {
            const response = await fetch("https://api.example.com/data");
            const result = await response.json();
            setData(result);
        } finally {
            setLoading(false);
        }
    }

    return html`
        <div>
            ${loading ? html`<p>Загрузка данных...</p>` : html`<button onCl ick=${fetchData}>Загрузить</button>`}
            ${data && html`<pre>${JSON.stringify(data, null, 2)}</pre>`}
        </div>
    `;
}

export default c(DataFetcher);

Ключевые моменты:

  • useState(false) создаёт начальное состояние loading.
  • Перед началом асинхронной операции setLoading(true) активирует индикатор загрузки.
  • После завершения операции, независимо от успеха или ошибки, setLoading(false) возвращает компонент в нормальное состояние.

Использование состояния loading позволяет отображать прогресс, блокировать кнопки или показывать скелетоны интерфейса, обеспечивая плавный UX.


Состояние error

Состояние error фиксирует возникновение ошибок во время асинхронных операций. Оно также создаётся через useState и обычно используется вместе с loading:

import { c, useState, html } from "atomico";

function DataFetcher() {
    const [loading, setLoading] = useState(false);
    const [data, setData] = useState(null);
    const [error, setError] = useState(null);

    async function fetchData() {
        setLoading(true);
        setError(null);
        try {
            const response = await fetch("https://api.example.com/data");
            if (!response.ok) throw new Error("Ошибка запроса");
            const result = await response.json();
            setData(result);
        } catch (err) {
            setError(err.message);
        } finally {
            setLoading(false);
        }
    }

    return html`
        <div>
            ${loading && html`<p>Загрузка данных...</p>`}
            ${error && html`<p style="color:red;">Ошибка: ${error}</p>`}
            ${!loading && !error && html`<button onCl ick=${fetchData}>Загрузить данные</button>`}
            ${data && html`<pre>${JSON.stringify(data, null, 2)}</pre>`}
        </div>
    `;
}

export default c(DataFetcher);

Особенности:

  • Состояние error инициализируется как null и сбрасывается перед каждой новой попыткой запроса.
  • Ошибки можно получать из исключений try/catch или проверять статус ответа сервера (response.ok).
  • Отдельное отображение ошибки позволяет гибко менять UI, например, показывать уведомления или блоки с повторной загрузкой.

Совместное использование loading и error

Для комплексной обработки асинхронных операций рекомендуется использовать состояния loading, error и данные (data) вместе. Это обеспечивает корректное управление всеми возможными состояниями компонента:

  1. Начало загрузки: loading = true, error = null
  2. Успешная загрузка: loading = false, data заполнено, error = null
  3. Ошибка: loading = false, error заполнено, data может быть null

Пример с добавлением кнопки повторной попытки:

${error && html`
    <p style="color:red;">Ошибка: ${error}</p>
    <button onCl ick=${fetchData}>Попробовать снова</button>
`}

Такой подход позволяет создавать надёжные, отзывчивые интерфейсы, которые реагируют на изменения состояния асинхронных операций и дают пользователю понятную обратную связь.


Рекомендации по организации состояния

  • Разделять состояние загрузки и ошибки для разных операций, если компонент выполняет несколько асинхронных задач одновременно.
  • Для сложных компонентов можно использовать объект состояния:
const [state, setState] = useState({
    loading: false,
    error: null,
    data: null
});
  • Изменения состояния через один объект позволяют централизованно управлять всеми параметрами и минимизировать дублирование кода.

Состояния loading и error в Atomico — фундаментальные инструменты для построения реактивных компонентов с асинхронными операциями, обеспечивающие предсказуемое поведение интерфейса и удобство взаимодействия пользователя с приложением.