Декларативное программирование в контексте Stimulus

Stimulus — это JavaScript-фреймворк, ориентированный на декларативное связывание поведения с HTML. В отличие от крупных SPA-фреймворков, Stimulus не стремится полностью управлять состоянием страницы, а добавляет интерактивность к существующей разметке. Центральный принцип — контроллеры связываются с DOM через атрибуты, а не через сложные структуры данных или шаблоны.

Каждый контроллер в Stimulus — это класс JavaScript, который наследует базовый Controller. Контроллер может иметь несколько action и target, что позволяет управлять поведением элементов без ручного поиска элементов через document.querySelector.

import { Controller } from "@hotwired/stimulus"

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

  greet() {
    this.outputTarget.textContent = `Hello, ${this.nameTarget.value}!`
  }
}

В приведённом примере nameTarget и outputTarget связываются с HTML-элементами через атрибуты data-*, что полностью исключает необходимость писать дополнительный код поиска элементов.


Декларативные действия (Actions)

Actions — это способ указать, какое поведение должно произойти при событии, используя атрибут data-action. Формат атрибута:

[data-action="событие#метод"]

Пример использования:

<input data-action="input#greet" data-controller="hello" data-hello-target="name">
<div data-hello-target="output"></div>

Здесь при событии input вызывается метод greet контроллера hello. Stimulus автоматически передаёт контекст контроллера и связанные цели (targets) без дополнительной привязки обработчиков через addEventListener.


Targets: связь с элементами DOM

Targets обеспечивают декларативное связывание переменных контроллера с элементами DOM.

  • Объявляются через static targets = ["имя"].
  • Доступ к ним осуществляется через свойства this.[имя]Target для одного элемента и this.[имя]Targets для коллекции элементов.

Пример:

<div data-controller="counter">
  <button data-action="click#increment">+</button>
  <span data-counter-target="value">0</span>
</div>
export default class extends Controller {
  static targets = ["value"]

  increment() {
    this.valueTarget.textContent = parseInt(this.valueTarget.textContent) + 1
  }
}

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


Декларативные привязки данных (Values)

Stimulus поддерживает Values, которые позволяют задавать значения прямо в HTML и автоматически преобразовывать их в свойства контроллера. Формат:

data-[controller]-[name]-value="значение"

Пример:

<div data-controller="greeting" data-greeting-name-value="Alice"></div>

Контроллер:

export default class extends Controller {
  static values = { name: String }

  connect() {
    console.log(`Hello, ${this.nameValue}`)
  }
}

Values упрощают работу с динамическими данными, позволяя контроллеру оставаться декларативным и предсказуемым.


Lifecycle callbacks

Stimulus предоставляет жизненный цикл контроллеров, который позволяет управлять состоянием при подключении и отключении элементов:

  • connect() — вызывается при инициализации контроллера и связывании с DOM.
  • disconnect() — вызывается при удалении элемента.
  • initialize() — вызывается перед connect, для начальной настройки.

Пример:

export default class extends Controller {
  connect() {
    console.log("Контроллер подключен")
  }

  disconnect() {
    console.log("Контроллер отключён")
  }
}

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


Работа с несколькими контроллерами

Stimulus поддерживает множественные контроллеры на одном элементе. Атрибуты data-controller могут содержать список через пробел:

<div data-controller="tooltip modal"></div>

Каждый контроллер независимо управляет своими targets, actions и values, что обеспечивает модульность и чистоту кода.


Интеграция с существующим HTML

Stimulus создан для декларативного улучшения серверного HTML. В отличие от SPA-фреймворков, нет необходимости создавать отдельные шаблоны или управлять состоянием в виртуальном DOM. Все связи описываются через data-атрибуты, что делает проект легко поддерживаемым.

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

<button data-controller="like" data-action="click#toggle" data-like-count-value="0">
  <span data-like-target="count">0</span> ❤️
</button>

Контроллер:

export default class extends Controller {
  static targets = ["count"]
  static values = { count: Number }

  toggle() {
    this.countValue++
    this.countTarget.textContent = this.countValue
  }
}

Такое решение декларативно и минималистично, позволяя быстро добавлять интерактивность.


Основные преимущества декларативного подхода в Stimulus

  • Простота и читабельность: поведение привязано напрямую к элементам HTML.
  • Минимизация ручного поиска элементов: все targets и actions задаются через атрибуты.
  • Модульность: каждый контроллер автономен.
  • Предсказуемость: значения (values) и жизненный цикл обеспечивают прозрачное управление состоянием.
  • Лёгкая интеграция с серверным рендерингом: идеально подходит для Rails, Django, Phoenix и других фреймворков.

Stimulus превращает обычный HTML в интерактивный, сохраняя его структурную чистоту и снижая количество JavaScript-кода, необходимого для динамических интерфейсов.