Don't Overuse `connect` New

by Julian Rubisch

The connect lifecycle callback is the most used hook to set up a controller when it is (in some circumstances repeatedly) connected to the DOM.

It is the correct place to instantiate any 3rd party plugins, such as Swiper, Dropzone, Chartjs, Threejs etc. It is also the best place to put any preconditions or cleanup of the DOM, for example based on browser capabilities.

It might not be the best place to

Bad

<div data-controller="toggle">
  <button data-toggle-target="button">Click to open</button> 
  <div data-toggle-target="panel" class="hidden">
    <!-- ... -->
  </div>
</div>

// toggle_controller.js
import { Controller } from "@hotwired/stimulus";

export default class extends Controller {
  static targets = ["button", "panel"];

  connect() {
    this.open = false;
    this.buttonTarget.addEventListener("click", this.toggle.bind(this));
  }

  toggle() {
    this.open = !this.open;
    this.panelTarget.classList.toggle("hidden");
  }
}

Good

<div data-controller="toggle" 
  data-toggle-open-value="false"
  data-toggle-hidden-class="hidden">
  <button data-action="toggle#toggle">Click to open</button> 
  <div data-toggle-target="panel" class="hidden">
    <!-- ... -->
  </div>
</div>

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

export default class extends Controller {
  static values = { open: Boolean };
  static targets = ["panel"];
  static classes = ["hidden"];

  toggle() {
    this.openValue = !this.openValue;
  }

  openValueChanged() {
    if(this.openValue) {
      this.panelTarget.classList.add(this.hiddenClass);
    } else {
      this.panelTarget.classList.remove(this.hiddenClass);
    }
  }
}

Rationale

One of the reasons for the rules above is that putting every type of setup there will bloat it and make it confusing to read. It will potentially also lead to violations of the Single Responsibility Principle because it’s easy to add more generic code that will eventually blur boundaries. The Open Close Principle has a good example.

Contraindications

These are mere guidelines, of course. Sometimes you cannot use values to hold state, because it might not be serializable (such as with whole instances of Swiper, etc.). Sometimes you have to listen for events but not trigger a Stimulus action, but call a private method. The lines are blurry of course, but when in doubt, I’d advocate to try and follow these rules of thumb.