Listen for and debounce Window Resize Event in Vue.JS
Tags: vue, performance, javascript, tutorial
Published: 2021-11-10 19:08:55

*Learn how to listen for a resize event in Vue and how to debounce the handler function to improve performance.*

At some point you will probably need to get information about the changing size of the browser window. You might want it for calculating the position of other elements on the page, such as keeping an element a certain distance from the bottom of the page no matter how tall the window is.

One way to do this in Vue.js is to add an event listener to track a '[resize](https://developer.mozilla.org/en-US/docs/Web/API/Window/resize_event)' of the window. I'll walk you through how you can do this in Vue. Let's get started!

## Set up initial height/width and listen for change to that height/width:

Since we want to track the change in height and width of the window, we will create a data property for height and width. This now gives us a place to hold on to that information about height and width.

```javascript
data() {
    return {
      height: 0,
      width: 0
    };
  },
```

We need to do three things to track the change in height/width. We need to: 

 - Add an event listener during the **created** lifecycle hook to listen for 'resize'.
 - Remove the event listener during the **destroyed** lifecycle hook to stop listening for 'resize'.
 - Set the initial height/width when the component mounts. We will set it during the **mounted** lifecycle hook using the `window.innerHeight` and `window.innerWidth` properities. 

Here is how we add the event listener and remove the event listener:

```javascript
created()  {
	window.addEventListener("resize", this.resizeHandler);
},

destroyed()  {
	window.removeEventListener("resize", this.resizeHandler);
},
```
Notice the method `resizeHandler`. We will have to add logic for that method in the component's **methods** object, but we'll get to that in a bit.

Here is how we set the initial height and width of the window when the component mounts. This ensures that when the component mounts, we have set the height and width properties to the actual height and width of the browser initially. After that, the event listeners will track the change from that starting height and width.

```javascript
mounted()  {
	this.height =  window.innerHeight;
	this.width =  window.innerWidth;
},
```

## Resize handler method

In the mounted hook, we set the initial height and width. We also want to do that constantly as the window is resized, so we will create a method with that same logic. And the method will run as the broswer listens for that event.

Here is the method:

```javascript
methods:  {
	resizeHandler(e)  {
		this.height =  window.innerHeight;
		this.width =  window.innerWidth;
	},
},
```

Remember, this is the method that is called as the event listener fires:

```javascript
window.addEventListener("resize",  this.resizeHandler);
```

## See it working
We can watch the data for height and width change as the window is resized. Put this in your Vue template:

```html
<template>
	<div  id="app">
		<div>Height: {{ height }}</div>
		<div>Width: {{ width }}</div>
	</div>
</template>
```
Then change the window size and watch the numbers react to that change. You can see a demo Codepen [here](https://codepen.io/sandrarodgers/pen/RwZBGXZ). 

## BONUS: debounce to improve performance

An event listener that fires constantly like this one can take a toll on performance. It's really smart to add a function that will debounce the event listener. Debounce means that instead of the `handleResize` function running each time the event fires, we add a timeout to cause the function to fire only after a certain time. **We limit the amount of time the handler function will fire, so the browser doesn't get bogged down trying to keep up with the constant firing of the resize event.**  Since a resize event happens so quickly, and the event would fire so often, we can limit it and it won't be noticeable to the user, as long as the timeout we put on it isn't for too long a duration.

We can add debouncing by using a kind of middleman on the height/width property. We will compute the height and width using a getter and a setter. So we will need to change our data properties to reflect that they are holding the debounced height and width, and then we will use the computed property to put a timeout on the height/width that is returned. 

```javascript
data()  {
	return  {
		debouncedHeight:  0,
		debouncedWidth:  0,
		heightTimeout:  null,
		widthTimeout:  null,
	};
},

computed:  {
	height:  {
		get()  
			return  this.debouncedHeight;
		},
		set(val)  {
			if  (this.heightTimeout)  clearTimeout(this.heightTimeout);
				this.heightTimeout =  setTimeout(()  =>  {
				this.debouncedHeight = val;
			},  500);
		},
	},

width:  {
	get()  {
		return  this.debouncedWidth;
	},
		set(val)  {
			if  (this.widthTimeout)  clearTimeout(this.widthTimeout);
				this.widthTimeout =  setTimeout(()  =>  {
				this.debouncedWidth = val;
			},  500);
		},
	},
},
```

Everything else remains the same, but now our height and width use the set method to slow down how rapidly they can actually be set, instead of setting them every time that resize event fires. You can see a working Codepen [here] (https://codepen.io/sandrarodgers/pen/porZbxW). I recommend slowing the timeout to really see how it works.

I hope this was helpful to you!