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.
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.
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.