REST интеграция

SkateJS — это легковесная библиотека для создания веб-компонентов с реактивной системой состояния и декларативным рендерингом. Одной из ключевых задач при работе с компонентами является интеграция с REST API для динамического получения и отправки данных. В этом разделе рассматривается организация REST взаимодействия внутри компонентов SkateJS, лучшие практики и особенности асинхронного управления состоянием.


Основы работы с REST в компонентах

Компоненты SkateJS строятся вокруг классов, наследующих Skate.Component, с декларативными свойствами (props) и реактивными состояниями. Для интеграции с REST обычно используется жизненный цикл компонента:

  • connectedCallback — вызывается при добавлении компонента в DOM.
  • disconnectedCallback — вызывается при удалении компонента из DOM.
  • UPDATEd — вызывается после изменения свойств или состояния компонента.

Запросы к REST API выполняются чаще всего внутри connectedCallback или при изменении входных свойств, которые влияют на данные.

Пример базового запроса в компоненте:

import { define, props, Component, h } from 'skatejs';

class UserList extends Component {
  static props = {
    apiEndpoint: props.string
  };

  users = [];

  connectedCallback() {
    super.connectedCallback();
    this.fetchUsers();
  }

  async fetchUsers() {
    try {
      const response = await fetch(this.apiEndpoint);
      if (!response.ok) throw new Error(`Ошибка сети: ${response.status}`);
      this.users = await response.json();
      this.update(); // триггер рендеринга после получения данных
    } catch (error) {
      console.error('Не удалось загрузить пользователей:', error);
    }
  }

  render() {
    return h('ul', {}, this.users.map(user => h('li', {}, user.name)));
  }
}

define('user-list', UserList);

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

  • Асинхронные запросы реализуются через async/await.
  • Любые изменения состояния компонента (this.users) требуют вызова this.update() для обновления DOM.
  • Обработка ошибок обязательна для обеспечения устойчивости компонента.

Реактивность и свойства

SkateJS использует реактивные свойства (props), что позволяет автоматически запускать методы при их изменении. Это особенно удобно для динамических REST запросов, зависящих от внешних параметров.

Пример обновления данных при смене API endpoint:

static props = {
  apiEndpoint: {
    ...props.string,
    attribute: true,
    se t(oldValue, newValue) {
      if (oldValue !== newValue) {
        this.fetchUsers();
      }
      return newValue;
    }
  }
};

Здесь:

  • attribute: true делает свойство доступным через HTML атрибут.
  • Кастомный set позволяет реагировать на изменение значения и запускать повторный запрос.

Управление состоянием загрузки и ошибок

Для улучшения UX часто добавляют индикаторы загрузки и обработку ошибок:

loading = false;
error = null;

async fetchUsers() {
  this.loading = true;
  this.error = null;
  this.update();

  try {
    const response = await fetch(this.apiEndpoint);
    if (!response.ok) throw new Error(`Ошибка сети: ${response.status}`);
    this.users = await response.json();
  } catch (err) {
    this.error = err.message;
  } finally {
    this.loading = false;
    this.update();
  }
}

render() {
  if (this.loading) return h('p', {}, 'Загрузка...');
  if (this.error) return h('p', {}, `Ошибка: ${this.error}`);
  return h('ul', {}, this.users.map(user => h('li', {}, user.name)));
}

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


POST, PUT и DELETE запросы

REST интеграция в SkateJS не ограничивается GET. Асинхронные методы POST, PUT и DELETE реализуются аналогично с использованием fetch, передавая необходимые параметры и тело запроса:

async addUser(user) {
  try {
    const response = await fetch(this.apiEndpoint, {
      method: 'POST',
      headers: { 'Content-Type': 'application/json' },
      body: JSON.stringify(user)
    });
    if (!response.ok) throw new Error(`Ошибка: ${response.status}`);
    const newUser = await response.json();
    this.users.push(newUser);
    this.update();
  } catch (err) {
    console.error('Не удалось добавить пользователя:', err);
  }
}

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

  • JSON тело запроса формируется через JSON.stringify.
  • После успешного добавления необходимо обновить локальное состояние компонента.
  • Обработка ошибок критична для сохранения корректного состояния UI.

Работа с зависимыми компонентами и подписками

Если несколько компонентов зависят от одних и тех же REST данных, рекомендуется использовать внешнее состояние (например, глобальный store или context) и подписку на его изменения. В SkateJS это может быть реализовано через реактивные свойства или события:

this.dispatchEvent(new CustomEvent('users-updated', { detail: this.users }));

Другие компоненты могут слушать это событие и синхронизировать своё состояние.


Лайфхаки при интеграции REST

  1. Кеширование — хранение данных между запросами уменьшает количество сетевых вызовов.
  2. Отмена предыдущих запросов — полезно при быстром изменении входных свойств, чтобы не обновлять компонент устаревшими данными (AbortController).
  3. Дебаунс — при автозаполнении или фильтрации данных задержка перед запросом снижает нагрузку на API.

Пример отмены устаревшего запроса:

abortController = null;

async fetchUsers() {
  if (this.abortController) this.abortController.abort();
  this.abortController = new AbortController();
  try {
    const response = await fetch(this.apiEndpoint, { signal: this.abortController.signal });
    this.users = await response.json();
    this.update();
  } catch (err) {
    if (err.name !== 'AbortError') console.error(err);
  }
}

Вывод

REST интеграция в SkateJS строится на асинхронных методах внутри компонентов, реактивных свойствах и корректном управлении состоянием. Правильная организация запроса, обработки ошибок и обновления UI обеспечивает высокую отзывчивость компонентов и удобство масштабирования.