There are several methods that can be used for inter-component communication in Vue.js. Normal props and events should be sufficient for most cases, but there are other methods available at your disposal as well.
Props & Events
Of course, the normal method for communication involves props and events. This common pattern provides a powerful way of communicating between components without introducing any dependency or limitations on which components are involved.
Props:
Props allow you to pass any data type to a child component, and allow you to control what sort of data your component receives. Prop updates are also reactive, allowing a child component to update whenever parent data changes.
Template Usage:
<my-component v-bind:prop1="parentValue"></my-component> <!-- Or more succinctly, --> <my-component :prop1="parentValue"></my-component>
Events:
Events provide a way to inform your parent components of changes in children.
Template Usage:
<my-component v-on:myEvent="parentHandler"></my-component> <!-- Or more succinctly, --> <my-component @myEvent="parentHandler"></my-component>
Firing an Event:
... export default { methods: { fireEvent() { this.$emit('myEvent', eventValueOne, eventValueTwo); } } }
Additionally, you can create global event buses to pass events anywhere in your app. We’ve got an article on that.
Combined:
Using v-model allows for combining props with events for two-way binding. This is often used for input components. v-model assumes the value prop and input event, but this can be customized.
Template Usage:
<my-component v-model="prop1"></my-component>
A v-model compatible component:
<template> <div> <input type="text" :value="value" @input="triggerEvent"/> </div> </template> <script> export default { props: { value: String }, methods: { triggerEvent(event) { this.$emit('input', event.target.value); } } } </script>
Use When: You need to do pretty much any sort of data passing and messaging between components.
Provide / Inject
A much newer addition to Vue is the provide / inject mechanism. It allows for selective exposition of data or methods from an ancestor component to all of its descendants. While provide / inject is not itself reactive, it can be used to pass reactive objects.
provide / inject is probably not a good idea to develop an app with, but it can come in quite handy when writing whole custom-rendered component libraries.
Ancestor Component:
const SomethingAllDescendantsNeed = 'Air, probably.'; export default { provide: { SomethingAllDescendantsNeed } }
Descendant Component(s):
export default { inject: ['SomethingAllDescendantsNeed'], mounted() { console.log(this.SomethingAllDescendantsNeed); } }
Template Usage:
<ancestor-component> <div> <descendant-component> <p> <descendant-component></descendant-component> </p> </descendant-component> </div> </ancestor-component>
(All descendant components, no matter how deep in the tree, have access to SomethingAllDescendantsNeed.)
Use When: Child components need access to an instance of something that’s only instantiated once per component tree. (Perhaps another library or an event bus.)
Direct Access
CAUTION: HERE BE SHARKS!
If you really, really, really, neeeeed to access a property or method directly on a parent or child component, you can use every component’s this.$parent and this.$children properties to have full access to everything on parent and children components. This is, however, and absolutely, horribly, despicably, terrible idea. If you find yourself in a situation where you need to do this, there’s a 99.99958% chance you did something wrong and should refactor.
Use When: DON’T. JUST DON’T.
Why not? Because you are introducing a direct coupling between both the implementation and structure in markup between parent and children components, making them inflexible and ridiculously easy to break.