Coding / Programming Videos

Post your favorite coding videos and share them with others!

Reactive Window Parameters in VueJS – James Wee – Medium

Source link

Wouldn’t it be nice if browser window parameters were reactive and you can do things like watching window.scrollY or window.innerWidth values in your whole application? Parameters like (but not limited to):


At this moment, there’s no way in VueJS to natively “watch” a window property or making it reactive. I couldn’t find a way to make scrollY reactive in many places efficiently in my application. I also didn’t want to add boilerplate like the ones below to each of my Vue Single File Components:

created () {
this.$el.addEventListener('click', this.someMethod)
destroyed () {
this.$el.removeEventListener('click', () => this.someMethod)

Doing this in multiple components really makes me feel bad for having to do such cumbersome operation over and over again. It’s also not performant and opens me up to possibility of user error if I forgot to add the destroyed() lifecycle.

Introducing EventBus

Vue is capable of creating another truly independent component that is decoupled from your DOM tree. This is called the “EventBus”.

EventBus is mainly used for parent child component communication. Personally that is just bad practise and that’s why EventBus is getting such bad reps. I believe application state should be managed in Vuex unless there is a really tight relationship between the parent and the child component.

Question: Why not just use Vuex to manage it like you’ve just said?

The reason I am not managing window interface using Vuex is because of decluttering. I only want Vuex to manage “application state” and window.scrollY definitely does not fall into the category of application state. Also, I’m trying to prevent my Vue devtools to look like this whenever scroll event is fired.

Mutation spam @[email protected]

This puts Vuex completely off the table. Let’s explore “EventBus” further.

Window State Management Using EventBus

I believe I have found a use-case for EventBus.

The main thing that we want to achieve here is reactivity. Example, if scrollY changes, I want that to trigger some change in a computed method in my app components.

With that in mind, let’s create a “WindowEventBus”.

With this, we have created a clone of the window interface and scrollY is reactive. Now let’s try to use it somewhere.

Let’s import this in App.js first to “inititalize” the component:

// App.js
import WindowEventBus from './WindowEventBus.js'

This will trigger the create() lifecycle of WindowEventBus and register the scroll event listener to window.

Now in my components. All I need to do is map it to a computed prop.

// AppNav.vue
import WindowEventBus from './WindowEventBus.js'
export default {
computed: {
scrollY () { return WindowEventBus.scrollY }

This is similar to using mapState introduced by Vuex. What we are doing here is mapping a computed value of this.scrollY to WindowEventBus.scrollY.

Now it is reactive and we can use it in another computed properties, such as:

// AppNav.vue
import WindowEventBus from './WindowEventBus.js'
export default {
computed: {
scrollY () { return WindowEventBus.scrollY },
isCollapsed () {
return this.scrollY < 100

With this setup, I have only ONE event listener in WindowEventBus. My component is squeaky clean. I can even do complicated things related to the window interface in WindowEventBus; and they will be reactive as well throughout the entire application.

Best part about this is it doesn’t spam my dev-tools with unnecessary mutations. Best of both worlds IMO.

The only downside I see from this setup is dev-tools does not support EventBus. So it’s going to be harder to debug WindowEventBus.js. I would make it a point to ensure that EventBus is a simple and straightforward component.

I’m using this on both my Vue and Nuxt applications and they have served me well.

That’s it!

Thanks for reading. I hope I have delivered value and have helped you. Would love to hear what you guys think about this approach and happy to hear your suggestions on how to improve this.

If you like the content, connect with me on Twitter and Instagram.

Source link


Leave a Reply

Please Login to comment
Notify of
Translate »