Stephen
Stephen

Reputation: 8218

Vue.js: EventBus.$on received value is not propagating

I am fairly new to vue and trying to figure out the best way to structure my event bus. I have a main layout view (Main.vue) inside of which I have a router view that I am passing a child's emitted info to like so:

<template>
<layout>
<router-view :updatedlist="mainupdate" />
</layout>
</template>
import { EventBus } from './event-bus.js'
export default {
  data () {
    return {
      mainupdate: []
    }
  },
mounted () {
    EventBus.$on('listupdated', item => {
      this.mainupdate = item
      console.log(item)
    })
  }
}

The structure looks like: Main.vue contains Hello.vue which calls axios data that it feeds to child components Barchart.vue, Piechart.vue, and Datatable.vue

The axios call in Hello.vue populates a data property called list. I then check if updatedlist (passed as router prop from Datatable.vue to Main.vue when something changes) is empty, and if so set it to the value of list

I know that the event is being emitted and received by Main.vue because the console.log(item) shows the data. But my child components are not getting updated, even though they are using updatedlist as their data source. (If I reload the page, they will be updated btw, but why aren't they reactive?)

UPDATE: I thought I would cut out the top level parent Main.vue and just put my EventBus$on inside Hello.vue instead and then just change list when it was received. But this does two things, neither of which are great:

  1. On every page refresh, my console logs add one more log to the list and output all of them. So for example if I have made 3 changes, there will be three logs, 4 there will be 4, etc. The list grows until I restart the app.
  2. My child components are STILL not updated :(

UPDATE 2: UGH. I think I see why they aren't updating, the problem is with the reactivity in my chartsjs component, so I will have to resolve that there (Barchart.vue, Piechart.vue). A simple component I built myself to just read the total length DOES get updated, so that works. This still leaves the mystery of the massive number of duplicate console logs though, any ideas?

Upvotes: 0

Views: 4317

Answers (2)

Bert
Bert

Reputation: 82459

It sounds like you may have the answer to the original question? To answer your last update you likely have duplicate logs because you do not appear to be removing event handlers. When you add an event handler to a bus like this:

mounted () {
    EventBus.$on('listupdated', item => {
      this.mainupdate = item
      console.log(item)
    })
  }
}

You need to remove it yourself. Otherwise you are just adding a new handler every time the component is mounted.

I suggest you move the actual handler into a method:

methods: {
  onListUpdated(item){
     this.mainupdate = item
     console.log(item)
  }
}

Move code to add the handler to created:

created() {
    EventBus.$on('listupdated', this.onListUpdate)
  }
}

And add a beforeDestroy handler:

beforeDestroy(){
   EventBus.$off("listupdated", this.onListUpdate)
}

And do that in every component that you are adding event handlers to EventBus.

Upvotes: 3

Frnak
Frnak

Reputation: 6802

I' not aware if you require to stick to the current structure. For me the following works perfectly fine.

// whereever you bootstrap your vue.js
// e.g.
window.Vue = require('vue');

// add a central event bus
Vue.prototype.$bus = new Vue();

Now you can simply access the event bus in every component by using

this.$bus.$on( ... )

As said I'm not aware of your full event bus code but this should actually work fine

Upvotes: 0

Related Questions