Контроллеры: определение и жизненный цикл

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

Определение контроллера

Контроллер в Stimulus представляет собой класс, унаследованный от Stimulus.Controller. Его основная задача — инкапсулировать логику взаимодействия с DOM-элементами, управлять состоянием и реагировать на события.

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

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

  connect() {
    this.outputTarget.textContent = "Контроллер подключен!";
  }

  greet() {
    console.log("Привет от Stimulus-контроллера!");
  }
}

Ключевые моменты определения:

  • static targets — массив имен целей (targets), через которые контроллер получает доступ к элементам DOM.
  • Методы класса могут вызываться напрямую через действия (actions), указанные в HTML.
  • Метод connect() вызывается при подключении контроллера к DOM-элементу.

Жизненный цикл контроллера

Контроллер Stimulus проходит несколько стадий, которые формируют его жизненный цикл:

  1. Инициализация

    • Контроллер создаётся при обнаружении соответствующего атрибута data-controller на элементе DOM.
    • На этом этапе происходит установка всех target и value, но DOM еще не полностью готов к взаимодействию.
  2. Подключение (connect)

    • Метод connect() вызывается сразу после вставки элемента в DOM.
    • Это подходящее место для инициализации состояния, подписки на события или модификации DOM.
    • Вызывается один раз для каждого экземпляра контроллера при подключении.
  3. Отключение (disconnect)

    • Метод disconnect() вызывается при удалении элемента из DOM.
    • Здесь можно очищать таймеры, отписываться от событий и освобождать ресурсы.
    • Очень важен для предотвращения утечек памяти при динамическом обновлении интерфейса.
  4. Обновление (initialize)

    • Метод initialize() вызывается при создании экземпляра контроллера до подключения к DOM.
    • Используется для установки начальных значений, конфигураций и внутреннего состояния.

Цели и действия

Stimulus использует два ключевых механизма для взаимодействия с DOM: targets и actions.

  • Targets

    • Позволяют получать ссылки на элементы DOM внутри контроллера.
    • Определяются через data-<controller>-target="имя" в HTML.
    <div data-controller="hello">
      <span data-hello-target="output"></span>
    </div>

    В контроллере this.outputTarget будет ссылкой на span.

  • Actions

    • Связывают события DOM с методами контроллера.
    • Определяются через data-action="событие->контроллер#метод".
    <button data-action="click->hello#greet">Сказать привет</button>

Value-объекты и реактивность

Stimulus поддерживает value-объекты, которые позволяют хранить реактивные данные прямо в DOM:

static values = { count: Number }

connect() {
  console.log(this.countValue)
}

increment() {
  this.countValue++
}

HTML:

<div data-controller="counter" data-counter-count-value="0">
  <button data-action="click->counter#increment">+</button>
</div>
  • Значения автоматически парсятся из атрибутов DOM.
  • Изменение value через this.countValue = ... обновляет внутреннее состояние контроллера, но не изменяет DOM напрямую (для этого нужно использовать targets).

Расширенные возможности жизненного цикла

  • Multiple targets — один и тот же target может быть массивом, если указано несколько элементов с одинаковым target.
  • Custom events — можно инициировать собственные события на targets для взаимодействия между контроллерами.
  • Inheritance — контроллеры могут наследовать поведение друг от друга, расширяя жизненный цикл.
export default class ExtendedController extends BaseController {
  connect() {
    super.connect();
    console.log("Дополнительная логика при подключении");
  }
}

Практические рекомендации

  • Всегда использовать disconnect() для очистки слушателей и таймеров.
  • Инициализация через initialize() должна быть минимальной, чтобы не блокировать DOM.
  • Использовать targets и actions вместо прямого поиска элементов через querySelector, чтобы сохранить декларативность и поддерживаемость кода.
  • Разделять контроллеры по функциональным областям: один контроллер — одна ответственность.

Stimulus предлагает простой, но мощный подход к управлению поведением элементов DOM, где жизненный цикл контроллера обеспечивает чистое управление ресурсами и упрощает масштабирование приложений.