1

Never used Vue.js before. I have one parent component and 2 child components. These 2 child components should interact with asynchronous actions using the native Vue event bus system (with a dummy Vue object used as a shared container for the event bus).

Having something like the following:

EventBus.js

import Vue from "vue"
export default new Vue()

Parent.vue

import Child1 from "./Child1.vue"
import Child2 from "./Child2.vue"

export default {

    name: "Parent",

    components: {
        child1: Child1,
        child2: Child2,
    }

}

Child1.vue

import EventBus from "./EventBus"

export default {

    name: "Child1",

    beforeCreate () {

        EventBus.$once("MY_EVENT_X", async () => {
            EventBus.$emit("MY_EVENT_Y")
        })

    },

    mounted () {
        // something
    }

}

Child2.vue

import EventBus from "./EventBus"

export default {

    name: "Child2",

    beforeCreate () {

        EventBus.$once("MY_EVENT_Y", async () => {
            // do something 
        })

    },

    mounted () {
        EventBus.$emit("MY_EVENT_X")
    }

}

My question: having the events handlers defined in the "beforeCreate" hook, can I be sure that the "beforeCreate" hooks of both Child1 and Child2 components will be initiliazed before any of the "mounted" hooks of Child1 or Child2 will be called by Vue?

revy
  • 3,945
  • 7
  • 40
  • 85

1 Answers1

2

You can leverage component hook order between parent and children. When parent mounted is called, we will be sure all child components is created and mounted.

enter image description here

Image source from here

To do it, you can define a boolean flag in parent, change this flag to true in mounted hook:

import Child1 from "./Child1.vue"
import Child2 from "./Child2.vue"

export default {

    name: "Parent",

    components: {
        child1: Child1,
        child2: Child2,
    },
    data: () => ({
      isChildMounted: false
    }),
    mounted() {
      this.isChildMounted = true
    }
}

Make sure to pass this flag to children component:

<child-2 :isReady="isChildMounted" />

Finally, in child component, watching for props change. When the flag is changed to true, we know all child components is ready. It's time to emit event.

import EventBus from "./EventBus"

export default {
    name: "Child2",
    props: ['isReady'],
    beforeCreate () {
      EventBus.$once("MY_EVENT_Y", async () => {
          // do something 
      })
    },
    watch: {
      isReady: function (newVal) {
        if (newVal) {
          // all child component is ready
          EventBus.$emit("MY_EVENT_X")
        }
      }
    }
}
ittus
  • 21,730
  • 5
  • 57
  • 57
  • Hi, thanks for the answer. From the graph above I have to assume that each child is fully initialized in sequence, thus Vue calls all the hooks (in order) from Child1, then do the same for Child2. Is this correct? I was hoping instead that the hooks were called by Vue in an order like beforeCreate[Child1], beforeCreate[Child2], created[Child1], created[Child2], etc.. – revy Feb 18 '19 at 08:56
  • I'm not sure the rendering order of sibling components. But you can control it by above technique, or other technique in https://stackoverflow.com/questions/43071742/how-to-control-order-of-rendering-in-vue-js-for-sibling-component – ittus Feb 18 '19 at 09:13