Интеграция с fetch API

Stimulus — это минималистичный JavaScript-фреймворк, который позволяет связывать поведение с DOM через контроллеры. Одним из ключевых сценариев является взаимодействие с сервером для получения или отправки данных без перезагрузки страницы. Для этого активно используется Fetch API, обеспечивающий асинхронные HTTP-запросы.

Подключение Stimulus и создание контроллера

Для начала необходимо определить контроллер Stimulus и привязать его к DOM-элементу. Контроллер создается как класс, наследующийся от Controller, с методами для обработки событий. Пример базового контроллера:

import { Controller } from "@hotwired/stimulus";

export default class extends Controller {
  static targets = ["output"];

  async fetchData(event) {
    event.preventDefault();
    const url = this.data.get("url");

    try {
      const response = await fetch(url, {
        method: "GET",
        headers: { "Accept": "application/json" }
      });

      if (!response.ok) throw new Error(`Ошибка HTTP: ${response.status}`);
      
      const data = await response.json();
      this.outputTarget.textContent = JSON.stringify(data, null, 2);
    } catch (error) {
      console.error(error);
      this.outputTarget.textContent = "Произошла ошибка при загрузке данных.";
    }
  }
}

В этом примере:

  • static targets = ["output"] задает целевой элемент, куда будет выводиться результат запроса.
  • fetchData — асинхронный метод, использующий Fetch API для получения данных в формате JSON.
  • Обработка ошибок выполняется через конструкцию try…catch, что обеспечивает безопасное выполнение запроса.

Использование data-атрибутов для конфигурации

Stimulus позволяет передавать параметры через data-* атрибуты, что делает контроллеры гибкими и переиспользуемыми. Пример:

<div data-controller="api"
     data-api-url="/api/users"
     data-api-target="output">
  <button data-action="click->api#fetchData">Загрузить пользователей</button>
  <pre data-api-target="output"></pre>
</div>
  • data-api-url содержит адрес, по которому будет отправлен запрос.
  • data-api-target="output" связывает элемент <pre> с target output контроллера.

Обработка POST-запросов

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

async postData(event) {
  event.preventDefault();
  const url = this.data.get("url");
  const payload = { name: "John Doe", age: 30 };

  try {
    const response = await fetch(url, {
      method: "POST",
      headers: {
        "Content-Type": "application/json",
        "Accept": "application/json"
      },
      body: JSON.stringify(payload)
    });

    if (!response.ok) throw new Error(`Ошибка HTTP: ${response.status}`);

    const data = await response.json();
    this.outputTarget.textContent = `Пользователь создан: ${data.id}`;
  } catch (error) {
    console.error(error);
    this.outputTarget.textContent = "Не удалось создать пользователя.";
  }
}
  • Заголовок Content-Type: application/json указывает серверу, что данные передаются в формате JSON.
  • Метод JSON.stringify преобразует объект в JSON-строку.
  • Обработка ответа аналогична GET-запросу.

Обработка асинхронных событий формы

Stimulus удобно использовать для управления формами без перезагрузки страницы. Например:

<form data-controller="form" data-form-url="/api/submit" data-action="submit->form#submitForm">
  <input type="text" name="title" placeholder="Заголовок">
  <button type="submit">Отправить</button>
</form>
<pre data-form-target="output"></pre>

Контроллер:

export default class extends Controller {
  static targets = ["output"];

  async submitForm(event) {
    event.preventDefault();
    const formData = new FormData(event.target);
    const url = this.data.get("url");

    try {
      const response = await fetch(url, {
        method: "POST",
        body: formData
      });

      if (!response.ok) throw new Error(`Ошибка HTTP: ${response.status}`);

      const data = await response.json();
      this.outputTarget.textContent = `Форма успешно отправлена: ${data.status}`;
    } catch (error) {
      console.error(error);
      this.outputTarget.textContent = "Ошибка при отправке формы.";
    }
  }
}
  • Использование FormData позволяет автоматически сериализовать поля формы для отправки.
  • Stimulus связывает событие submit с методом submitForm, обеспечивая чистый и управляемый код.

Динамическое обновление интерфейса

При работе с Fetch API важно учитывать, что данные могут изменяться асинхронно. Stimulus облегчает динамическое обновление DOM:

this.outputTarget.innerHTML = data.map(user => `<li>${user.name}</li>`).join("");
  • innerHTML позволяет вставить структурированные элементы.
  • Комбинируя targets и actions, можно обновлять интерфейс в ответ на любые асинхронные события.

Обработка ошибок и загрузки

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

this.outputTarget.textContent = "Загрузка...";
  • Перед отправкой запроса интерфейс показывает состояние загрузки.
  • В блоке catch отображается сообщение об ошибке.
  • Это позволяет пользователю видеть актуальный статус операции без перезагрузки страницы.

Итоговая структура контроллера

Полезно группировать методы контроллера по типу операций:

  • fetchData — получение данных;
  • postData — отправка данных;
  • submitForm — обработка форм;
  • вспомогательные методы — обработка ошибок и обновление интерфейса.

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