Vue.js is a progressive JavaScript framework. Besides React, it’s one of the most popular ones, and its popularity has been steadily growing since it was released in 2014.
I like that it’s open source and very performant, and I personally find a certain kind of elegance in it’s simplicity.
While I was recently working on a project building a dashboard for a user system, I found myself sending data back and forth between components. It got me thinking about the best ways to do it. And that’s how this post was born – sharing all the ways in which you can send information between different parts of your app. And also examples of when to use each option.
Props – Sending data from parent to child
If you need to send a value from parent to child component then props are the way to go. They can be of different types (string, number,…) and you can do type validation to avoid potential errors. When the value of the prop changes in the parent component, it will be passed down to its children. Yes, a prop can be passed down to more child components. The children can however not change the prop as we want to avoid mutating the parent’s state. So the binding is one-sided.
Provide / Inject – Sending data without prop drilling
Sending data from a component that is high in the component tree to a deeply nested child can get tricky. If we do this with props then we need to pass the prop from component 1 to component 2, from component 2 to component 3, and all the way till we reach our destination. That can take quite a few steps and is known as prop drilling. To avoid it, and the confusion that it might bring, we have the provide/inject option. Inside the parent, we will have the provide function that accepts two arguments.
provide( injection key, provided value)
To get the data provided by the ancestor we use the inject function.
const injectedValue = inject( injection key )
You can use this to send data directly from your App.vue file and you can have multiple values provided with different keys for differentiation. It can be used with refs, just keep in mind that they are not automatically unwrapped (so use the properties like .value when needed).
Custom events – Sending info from child to parent component
So far it was the parent sending values, but what if we need to send info up the component tree? That’s where the custom events come into place. The child can communicate with the parent by triggering an event that the parent will then listen to.
Inside the child we will need to define emit and use it where needed:
const emit = defineEmits([‘close’]);
function handleLogOut() {
userStore.resetUsername();
userStore.setLogIn(false);
localStorage.removeItem(“user”);
emit(“close”); //close the menu on log out
};
Inside the parent, we call the event:
<UserMenu @close=”closeDropdown” /> //calls the function closeDropdown that is defined in the parent component
In the example I took from my own project, I’m not passing any info, but emit accepts two parameters – the first one is the event name and the second one is data that we can pass up.
State management – Sharing info in a larger project
When scaling up it can be hard to keep track of all the data being sent and that’s where stores come into the picture. Using state management like Pinia or Vuex can really make your life easier. Defining stores that can manage data and the functionality around them makes Vue so much easier to use.
And there you have it – ways of passing data in Vue.js. I love all the options and the flexibility they give me. For smaller projects you have props, provide/inject, and custom events. For the bigger ones with more complexity, I would recommend mixing those with stores, depending on your needs. I personally turn to stores when I know that I need to pass a certain state between more components, and stick to other options if I need to share something once and just between two components. All the options can be quite useful and are great tools to use on both smaller and bigger projects.