Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Duplicate events being emitted from VueJS component

When my mouse cursor enters and leaves my VueJS component, the following methods are called respectively.

Methods that are called when the cursor enters and leaves my component:

// located in "methods" section of my Vue component file

onMouseEnter() {
    window.Event.$emit("mouse-entered", this.index);
    console.log("Mouse entered");
},
onMouseLeave() {
    window.Event.$emit("mouse-left", this.index);
    console.log("Mouse left");
},

Expectedly, this is what my console looks like when my cursor enters and leaves the component (one event is emitted each time):

enter image description here

However, what's really strange is that in Vue dev tools, I'm seeing duplicate events being emitted every time my cursor enters and leaves my component:

enter image description here

Given this conflicting information, I'm not sure what to believe. Refreshing the page sometimes eliminates the duplicate events in dev tools but I always get single, unique events in my console, which is my desired behaviour.

Does anyone know what is happening here and what should I accept as the source of truth?

Below is how my Vue instances are being declared and initialised in my main.js file:

// As far as I can tell, duplicated Vue instances are not being created here on page refresh

let app;

// global event bus
window.Event = new Vue();
console.log("Event bus created");

/* This section ensures the firebase auth object isn't in an intermediary state. */
firebase.auth().onAuthStateChanged(() => {
    if (!app) {
        console.log("New Vue instance created");
        app = new Vue({
            el: '#app',
            router,
            store,
            render: h => h(App)
        });
    }
});

Note that this particular component is being reused on two different routes( "dashboard" and "home" ), which are both being kept alive by the following code.

// Template section of App.vue file
<template>
    <div id="app">
        <keep-alive
            v-bind:include="[ 'dashboard', 'home' ]"
            <router-view></router-view>
        </keep-alive>
    </div>
</template>

Additionally, since those two routes are being kept alive and cached, failure to turn $off event emitters and listeners should not be the cause of duplication (at least I think it shouldn't).

EDIT 1: I did a find all for "mouse-entered" and "mouse-left" in every single directory in my project and I can confirm that both events are only emitted from the Vue component I've referenced to in this post.

EDIT 2: To help with debugging, I put a listener on my top-most component (App.vue) to see if it receives the event twice (refer to the created hook in the code snippet below). I can confirm it also only receives the event once. I've also pasted in my complete App.vue file since the above example was mainly to illustrate that I'm keeping alive "dashboard" and "home".

<template>
    <div id="app">
        <keep-alive
            v-bind:include="keepAlive">
            <router-view></router-view>
        </keep-alive>
    </div>
</template>

<script>
    export default {
        name: 'app',
        data() {
            return {
                isLoggedIn: false,
            };
        },
        computed: {
            keepAlive() {
                if (this.isLoggedIn) {
                    return [ 'dashboard', 'home', 'results' ];
                }
                return [ 'landing', 'signIn', 'signUp' ];
            }
        },
        watch: {
            /* This watches for route changes */
            $route(to, from) {
                /* firebase.auth().currentUser returns null if user has logged out */
                if (firebase.auth().currentUser) {
                    this.isLoggedIn = true;
                } else {
                    this.isLoggedIn = false;
                }
            }
        },
        created() {
            window.Event.$on("mouse-entered", () => {
                console.log("mouse-entered-from-App.vue");
            });
            window.Event.$on("mouse-left", () => {
                console.log("mouse-left-from-App.vue");
            });
        }
    };
</script>

As expected, App.vue receives the event once (see below); however, I'm still getting duplicate events in Vue dev tools :(

enter image description here

like image 269
p4t Avatar asked Jul 21 '18 14:07

p4t


1 Answers

You wrote

Refreshing the page sometimes eliminates the duplicate events in dev tools but I always get single, unique events in my console, which is my desired behaviour.

The way you describe your problem, the events are emitted correctly, while they are being reacted on in a wrong, duplicate way. I think what you might be missing is unsubscribing from your event bus once the component gets destroyed. You should use the beforeDestroy hook to do so (similar to the way you used created earlier on in the component's lifecycle to subscribe).

Something like this:

beforeDestroy() {
    window.Event.$off('mouse-entered');
    window.Event.$off('mouse-left');
}
like image 141
van-koelljor Avatar answered Oct 13 '22 01:10

van-koelljor