Discover the different ways to make components communicate in a Vue.js application.

Props

The first way is by using props. With props, parents pass data down to their child components by adding arguments to the component declaration. For example:

<template>
  <div>
    <Car color="green" />
  </div>
</template>

<script>
import Car from './components/Car'

export default {
  name: 'App',
  components: {
    Car
  }
}
</script>

Props are one-way, meaning data flows from the parent to the child. When the parent changes the prop, the new value is sent to the child and the child component is rerendered. However, the reverse is not true, and you should never mutate a prop inside a child component.

Events to communicate from children to parent

Events allow you to communicate from the child components up to the parent components. In the child component, you can emit an event using this.$emit:

<script>
export default {
  name: 'Car',
  methods: {
    handleClick: function() {
      this.$emit('clickedSomething')
    }
  }
}
</script>

The parent component can intercept this event using the v-on directive (or the shorthand @) when including the child component in its template:

<template>
  <div>
    <Car v-on:clickedSomething="handleClickInParent" />
    <!-- or -->
    <Car @clickedSomething="handleClickInParent" />
  </div>
</template>

<script>
export default {
  name: 'App',
  methods: {
    handleClickInParent: function() {
      //...
    }
  }
}
</script>

You can also pass parameters along with the emitted event in the child component and retrieve them in the parent component:

<script>
export default {
  name: 'Car',
  methods: {
    handleClick: function() {
      this.$emit('clickedSomething', param1, param2)
    }
  }
}
</script>
<template>
  <div>
    <Car v-on:clickedSomething="handleClickInParent" />
    <!-- or -->
    <Car @clickedSomething="handleClickInParent" />
  </div>
</template>

<script>
export default {
  name: 'App',
  methods: {
    handleClickInParent: function(param1, param2) {
      //...
    }
  }
}
</script>

Using an Event Bus to communicate between any component

Events are not limited to child-parent relationships. You can use an Event Bus to establish communication between any components. Instead of emitting the event on the component instance (this.$emit), you can emit the event on a more generally accessible component, such as this.$root (the root component).

Alternatively, you can create a dedicated Vue component specifically for event handling and import it where needed.

In the child component, you can emit the event on the root component or the dedicated component:

<script>
export default {
  name: 'Car',
  methods: {
    handleClick: function() {
      this.$root.$emit('clickedSomething')
    }
  }
}
</script>

Any other component can listen for this event. You can add this listener in the mounted callback of the component:

<script>
export default {
  name: 'App',
  mounted() {
    this.$root.$on('clickedSomething', () => {
      //...
    })
  }
}
</script>

Alternatives

While Vue.js provides props and events out of the box for component communication, there might come a time when you need more advanced state management. In such cases, you can explore libraries like Vuex or other third-party solutions.