paint-brush
A Guide to Handling Web Component Removal With DisconnectedCallbackby@raymondcamden
542 reads
542 reads

A Guide to Handling Web Component Removal With DisconnectedCallback

by Raymond CamdenJune 8th, 2023
Read on Terminal Reader
Read this story w/o Javascript
tldt arrow

Too Long; Didn't Read

MDN does a fairly good job of covering the lifecycle events for web components but one in particular got my attention today, disconnectedcallback. As kind of the inverse of connectedCallback, it will be fired when an instance of your custom element is removed from the DOM. While I didn't doubt this worked as advertised, I wanted to build a quick demo myself so I could see it in action. Let's start off with a component that demonstrates why this event is needed.
featured image - A Guide to Handling Web Component Removal With DisconnectedCallback
Raymond Camden HackerNoon profile picture

MDN does a fairly good job of covering the lifecycle events for web components but one in particular got my attention today, disconnectedcallback. As kind of the inverse of connectedCallback, it will be fired when an instance of your custom element is removed from the DOM. While I didn't doubt this worked as advertised, I wanted to build a quick demo myself so I could see it in action. Let's start off with a component that demonstrates why this event is needed.

Initial Web Component

The first draft of our component is foo-cat. This component does two things, outputs a simple bit of HTML and then uses an interval to execute code every two seconds. In this trivial example, it's just going to log a message to the DOM, but in a real-world component, you could imagine a component hitting a remote API to get updated information.


Here's the component:


class FooCat extends HTMLElement {
	constructor() {
		super();
	}

	connectedCallback() {
		let name = 'Nameless';
		if(this.hasAttribute('name')) name = this.getAttribute('name');
		this.innerHTML = `<p>"Meow, meow.", said ${name} the cat.</p>`;
		setInterval(() => {
			let p = document.createElement('p');
			p.innerText = 'Meow!';
			document.body.append(p);
		}, 2000);
	}

}

customElements.define('foo-cat', FooCat);


Now I'll use it in my HTML:


<foo-cat></foo-cat>
<button onclick="killTheCat()">Kill the Cat</button>


I've added a button as well and used an inline event handler (yes, this is not best practice, but I'm trying to keep things simple, please don't report me to the JavaScript Elders, I'd rather they keep fighting about React, SPAs, and, well everything else). The killtheCat function just removes the element using a document selector (technically this will only remove the first one in the DOM, but again, going for simplicity):


function killTheCat() {
	console.log('kill the cat');
	document.querySelector('foo-cat').remove();
}


Alright, nice and simple, right? Here it is running in a CodePen:


If you click the button, you'll notice the component goes away, but the messages keep getting printed to the page. If you want, you can open the CodePen link, go to devtools, and confirm the custom element is gone.

Fixed Component

I was going to label this section, "properly killing the cat", but thought that was a bit much. So as you can expect, having an event handler to recognize when the component leaves the DOM is exactly what we need to fix this issue. I made two changes. First, I kept a handle to my interval like so:


this.heartbeat = setInterval(() => {
	let p = document.createElement('p');
	p.innerText = 'Meow!';
	document.body.append(p);
}, 2000);


And then simply added the event handler:


disconnectedCallback() {
	console.log('i was killed, sad face');
	clearInterval(this.heartbeat);
}


So again, while my component here is pretty trivial, you can see how important this would be in a real-world web component. You can test this out yourself below.

Also published here.