Coding / Programming Videos

Post your favorite coding videos and share them with others!

Making DOM Window Params Reactive – James Wee – Medium

Source link

I am always trying to figure out ways to make window interface parameters reactive in my whole application. Parameters like (but not limited to):

window.scrollY
window.innerHeight
window.innerWidth

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 these kind of boilerplate to my components:

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

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 by not adding 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 manage it in Vuex 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 is definitely does not fall into the category of application state. Also, I’m trying to prevent my Vue dev-tools to look like this whenever scroll event is fired.

Mutation spam @[email protected]

With Vuex is completely off the table, I’ve explored “EventBus”.

Window State Management Using 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.

I would import this in App.js first to “inititalize” it.

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

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

Now in my components. All I need to do is

// 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 this.scrollY to WindowEventBus.scrollY.

Now we can use it for everything else. 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 such as calculating my scroll direction is up or down, and those are 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.

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

Bookmark(0)
 

Leave a Reply

Please Login to comment
  Subscribe  
Notify of
Translate »