we will use this sandbox to illustrate communication between different components, feel free to fork and play with it. I used tailwind for my styling. You'll need this when you have set a data property a component and you would like to render the data in another component or even mutate the data
parent to child communication
props allow one-way communication between a parent component and a child component. In the sandbox above, app.vue
is our parent component with role
as a data property, we want to pass the data from app component to ViewUser component, to do this we register a props property to ViewUser, this is an array with strings and in each string we specify properties which should be settable from outside, the name we set in our string has to match the name we use in our template.
To pass the prop we v-bind the prop name to the data property in the parent component where we render the template
<div class="flex"><ViewUser :role="role" /></div>
we can use props like a normal property, access it with this
and run a method like seen in the example
methods: {
reverseRole() {
return this.role
.split('')
.reverse()
.join('');
}
}
To validate props we use the object syntax. If a requirement isnโt met, Vue will warn you in the browserโs JavaScript console at development time
props: {
role: String
},
other validators to props are: Number, Boolean, Array, Object, Date, Function
and Symbol
child to parent
To demonstrate this we will make a button that will revert the role back to 'frontend developer' and pass the value from the child component- ViewUser.vue
to the root component which is app.vue
, for this we will use custom events. The child will emit a new event when data changes and the parent listens
when we initialize the vue instance we get the emit
method, on emit we specify the name we want to emit and the data as the second argument as this.$emit('rolewasreset', this.mutatedrole);
. we listen to the event emitted with the v-on directive or the shorthand @ in the selector of the component emitting the event inside the root component, the name must much the name we gave to emit event in our case the name was rolewasreset
passing the event
<ViewUser :role="role" @rolewasreset="role = $event;" />
note that we didn't mutate the prop directly but we defined a local data property that uses the prop as its initial value. if you do so you will get an warning in the console
sibling to sibling
For sibling to sibling communication, we will use eventBus. note that we can also use Vuex which we will not use in this example.
In our main.js, we create a new vue instance and store it in a constant which we export. we import in our edituser and viewuser where we emit the event and listen to the event respectively. eventBus is a vue instance, so we get the $emit method by default
in a method inside our edituser component we call eventbus passing the required parameters eventBus.$emit('ageWasEdited', this.newAge);
we listen to the event in our viewuser component inside the create lifecycle hook using eventBus.$on('ageWasEdited', newAge => {
this.newAge = newAge;
the first parameter is the name of the event while the second is the data which is always a callback.
if we also render age in our root component you will notice once we edit the age the change won't reflect, meaning data is not passed to the parent then to the child receiving the data.
Hope this helped you understand how to communicate between components
Top comments (3)
Note that the "sibling to sibling communication" you stated in the article is actually a global event bus which is a simple way of getting unrelated sections of your application to talk to each other. However, it is also considered an anti-pattern if not used correctly and it's really hard to maintain a medium-large codebase using exclusively this architecture. My recommendation would be: adopt vuex for everything as a default, and fall back to a global event bus if you think vuex becomes a substantial overhead in simple apps. I would only use a global event bus for events that don't necessarily mutate state or application data but only in rare cases/scenarios.
While it seems easier to set up and integrate a global event bus for "communicating between distant components", you will inevitably regret it once your app has achieved a certain size and level of complexity, especially once you need to refactor some of your views.
thanks for highlighting that
Don't forget to unbind the handler before destroying the component.
In your case:
Also, you'd better refactor your handler in a method to unbind it specifically.