Stimulus построен вокруг концепции контроллеров,
которые связывают HTML-элементы с поведением через
data-controller. В стандартной ситуации контроллеры
инициализируются один раз при загрузке страницы. Однако в динамических
интерфейсах, где DOM может меняться после первоначальной загрузки
(например, при подгрузке контента через AJAX или Turbo), возникает
необходимость реинициализации существующих контроллеров
и подключения новых к элементам, добавленным
динамически.
application.load()Stimulus предоставляет API для явной инициализации контроллеров.
Каждый экземпляр приложения Stimulus хранится в объекте
Application, который управляет жизненным циклом
контроллеров. После добавления нового элемента в DOM с атрибутом
data-controller можно вызвать:
import { Application } from "@hotwired/stimulus"
import HelloController from "./controllers/hello_controller"
const application = Application.start()
application.register("hello", HelloController)
// Динамически добавленный элемент
const newElement = document.createElement("div")
newElement.setAttribute("data-controller", "hello")
document.body.appendChild(newElement)
// Реинициализация
application.load(newElement)
Метод load() инициирует контроллеры только на
переданном элементе, что предотвращает повторную инициализацию
уже существующих контроллеров на других элементах.
Каждый контроллер Stimulus проходит через следующие стадии:
initialize() — выполняется один раз
при создании экземпляра, до привязки к элементу.connect() — вызывается при добавлении
элемента в DOM или при инициализации.disconnect() — вызывается при удалении
элемента из DOM.При динамическом добавлении элементов важно учитывать, что:
initialize() не вызовется повторно для
существующих контроллеров.connect() может быть вызван повторно только для новых
элементов, если они были зарегистрированы через
application.load().Это поведение гарантирует стабильность состояния контроллеров и предотвращает утечки памяти.
Stimulus позволяет добавлять контроллеры после старта
приложения, что особенно полезно при модульной загрузке
компонентов. Для этого используется метод
application.register(name, controllerClass). После
регистрации новые контроллеры автоматически инициализируются на
элементах с соответствующим data-controller.
Пример добавления контроллера после загрузки страницы:
import { Application } from "@hotwired/stimulus"
const application = Application.start()
// Поздняя регистрация контроллера
import ModalController from "./controllers/modal_controller"
application.register("modal", ModalController)
// Элемент уже находится в DOM
const modalElement = document.querySelector("#dynamic-modal")
// Контроллер автоматически инициализируется на modalElement
Если элемент создаётся динамически до регистрации
контроллера, потребуется вызвать
application.load(element) после регистрации.
Один элемент может иметь несколько контроллеров, указанных через
пробел в data-controller:
<div data-controller="tabs modal"></div>
Stimulus гарантирует, что каждый контроллер будет инициализирован отдельно. Для динамически добавленных элементов порядок действий:
application.load(newElement) для запуска всех
контроллеров на этом элементе.При динамическом добавлении элементов важно учитывать события жизненного цикла:
connect срабатывает сразу после инициализации
контроллера.disconnect — при удалении элемента, что позволяет
освобождать ресурсы, останавливать таймеры и отменять подписки на
события.Для элементов, которые добавляются и удаляются многократно,
рекомендуется использовать disconnect() для очистки
состояний и предотвращения утечек памяти:
export default class extends Controller {
connect() {
this.interval = setInterval(() => console.log("tick"), 1000)
}
disconnect() {
clearInterval(this.interval)
}
}
connect оставался лёгким, а сложные операции
выполнялись после полной готовности DOM.application.load(newContent).application.load(rowElement).Стратегия динамической реинициализации и регистрации контроллеров позволяет строить масштабируемые и поддерживаемые интерфейсы, сохраняя преимущества реактивного подхода Stimulus без необходимости полного перезапуска приложения.