Обработка состояний загрузки

В Slim.js состояние компонента определяется реактивными свойствами и наблюдаемыми изменениями данных. Для реализации логики загрузки используется комбинация реактивного состояния и условного рендеринга.

Создание реактивного свойства для состояния загрузки

Для отслеживания состояния загрузки необходимо определить свойство компонента, которое будет хранить булево значение:

import { Slim } from 'slim-js';

class LoadingComponent extends Slim {
  isLoading = false;

  constructor() {
    super();
  }

  startLoading() {
    this.isLoading = true;
  }

  stopLoading() {
    this.isLoading = false;
  }

  template() {
    return `
      <div>
        ${this.isLoading ? `<p>Загрузка данных...</p>` : `<p>Данные загружены</p>`}
        <button @click="fetchData">Загрузить</button>
      </div>
    `;
  }

  fetchData() {
    this.startLoading();
    fetch('https://api.example.com/data')
      .then(response => response.json())
      .then(data => {
        console.log(data);
        this.stopLoading();
      })
      .catch(() => {
        this.stopLoading();
      });
  }
}

customElements.define('loading-component', LoadingComponent);

Ключевой момент: isLoading автоматически отслеживается Slim.js, и любое изменение его значения вызывает обновление шаблона без дополнительного вмешательства.

Условный рендеринг и отображение индикатора

Slim.js позволяет использовать тернарные выражения внутри шаблона для отображения различных элементов в зависимости от состояния. Это упрощает реализацию индикатора загрузки:

${this.isLoading 
  ? `<div class="spinner"></div>` 
  : `<div class="content">Контент загружен</div>`}

Можно комбинировать несколько состояний для более сложной логики:

${this.isLoading 
  ? `<div class="spinner">Загрузка...</div>` 
  : this.error 
    ? `<div class="error">Ошибка загрузки</div>` 
    : `<div class="content">Данные готовы</div>`}

Работа с асинхронными операциями

Для интеграции с API или длительными процессами рекомендуется использовать методы класса для управления состоянием:

  1. Инициализация загрузки: установка isLoading = true.
  2. Асинхронная операция: fetch или async/await.
  3. Обработка результата: обновление данных компонента.
  4. Завершение загрузки: установка isLoading = false.

Пример с использованием async/await:

async fetchData() {
  try {
    this.startLoading();
    const response = await fetch('https://api.example.com/data');
    this.data = await response.json();
  } catch (err) {
    this.error = true;
  } finally {
    this.stopLoading();
  }
}

Важно: finally гарантирует, что индикатор загрузки будет скрыт независимо от исхода запроса.

Декоративные и визуальные элементы загрузки

Для улучшения UX используются спиннеры, прогресс-бары и анимации. Slim.js не ограничивает стандартные HTML и CSS, поэтому можно интегрировать любые визуальные компоненты:

<style>
  .spinner {
    border: 4px solid #f3f3f3;
    border-top: 4px solid #3498db;
    border-radius: 50%;
    width: 30px;
    height: 30px;
    animation: spin 1s linear infinite;
  }

  @keyframes spin {
    0% { transform: rotate(0deg); }
    100% { transform: rotate(360deg); }
  }
</style>

В шаблоне Slim.js это используется как обычный HTML-элемент:

${this.isLoading ? `<div class="spinner"></div>` : `<div>Контент загружен</div>`}

Управление несколькими параллельными загрузками

Если компонент выполняет несколько асинхронных операций одновременно, рекомендуется использовать счетчик загрузок вместо булева флага:

loadingCount = 0;

startLoading() {
  this.loadingCount++;
}

stopLoading() {
  if (this.loadingCount > 0) this.loadingCount--;
}

get isLoading() {
  return this.loadingCount > 0;
}

Такой подход предотвращает преждевременное скрытие индикатора при параллельных запросах.

Рекомендации по производительности

  • Использовать минимальное количество реактивных свойств, чтобы избежать лишних обновлений DOM.
  • Отдельные индикаторы для крупных компонентов лучше реализовывать как отдельные дочерние Slim-компоненты.
  • Асинхронные операции следует отменять при удалении компонента, чтобы избежать утечек памяти.

Интеграция с состояниями ошибок

Часто требуется одновременно обрабатывать загрузку и ошибки:

${this.isLoading
  ? `<p>Загрузка...</p>`
  : this.error
    ? `<p class="error">Ошибка при загрузке данных</p>`
    : `<p>Данные успешно загружены</p>`}

Реактивность Slim.js обеспечивает мгновенное обновление UI при смене состояния isLoading или error.


Хотите, я могу подготовить ещё один блок с примером сложного компонента с прогресс-баром и несколькими параллельными загрузками для Slim.js? Это будет логическое продолжение темы.