Why Disconnect in Stimulus Controllers

The disconnect lifecycle method in Stimulus is one of three lifecycle methods. The other two are initialize and connect. Disconnect gets called when the controller is removed from the DOM. For this, Stimulus uses mutation observers to track DOM elements.

Within the disconnect method you can do your teardown, clean up and whatever. The reasons to do this depends on your code, but range from preventing memory leaks, maintaining browser performance and preventing unexpected side effects.

Letā€™s look at some examples:

export default class extends Controller {
  connect() {
    this.interval = setInterval(() => {
      console.log("Run, Forrest, run!");
    }, 1000);
  }
}

Without clearing the interval, it will continue running in the background, causing a memory leak.

export default class extends Controller {
  disconnect() {
    clearInterval(this.interval);
  }
}

Or if you use a third-party library, like CodeMirror:

import { EditorView } from "@codemirror/view"

export default class extends Controller {
  connect() {
    this.editor = new EditorView();
  }
}

Clean up is simple:

import { EditorView } from "@codemirror/view"

export default class extends Controller {
  disconnect() {
    this.editor?.destroy();
  }
}

Without it any new instance of this.editor maintains their own state and the editorā€™s DOM elements might remain in memory.

Letā€™s look at one more that could possibly break your browser. šŸ’„

export default class extends Controller {
  connect() {
    navigator.mediaDevices.getUserMedia({ video: true })
      .then(stream => {
        this.videoStream = stream;
        this.element.srcObject = stream;
      });
  }
}

If you donā€™t stop the video-streams they will continue to run in the background. Then with multiple instances running this will result in high CPU usage and potentially crash the browser due to the lack of resources. šŸ˜¬

Letā€™s add a disconnect, shall we?

export default class extends Controller {
  disconnect() {
    this.videoStream.getTracks().forEach(track => track.stop());
  }
}

With these examples, I hope you will become a good citizen and clean up after yourself! šŸ˜Š

Get UI & Product Engineering Insights for Rails Apps (and product updates!)

Published at . Have suggestions or improvements on this content? Do reach out.

UI components for Ruby on Rails apps

$ 129 one-time
payment

Get Access
  • One-time Payment

  • Access to the Entire Library

  • Built for Ruby on Rails (inc. Rails 8)

  • Designed with Tailwind CSS and Enhanced with Hotwire

  • Updates for 12 months