When we’re working with a multi-layered Vue app, we typically utilize props to transfer data from a parent component to a child component. This has been made simple and easy to perform with Vue.js. However, passing data from a parent-level component to a nested child component that’s several levels deep has surely frustrated most Vue developers at some point.

If we were to use props, the data would ultimately need to be passed to every component on every level of the Vue component tree in order to reach its goal. Prop drilling is a technique that might make our app appear more complex than it really is. Additionally, if it were a straightforward application, utilizing something like Vuex or Pinia would be excessive.

We are fortunate to have Vue’s provide/inject API, which has never been better with the addition of the Composition API in Vue 3.

Nowadays, no matter how deep the component hierarchy is, parent components can send data to nested components using the native functions provide() and inject(). In this way, data can be supplied by the parent component using the provide function, and can be used by the child component using the inject method.

In this article, we’ll take a look at this new functionality and see how we can use it in our own projects. Let’s get started!

What is the provide/inject pair in Vue 3?

If we take a look at any standard Vue app, we’ll normally have several layers of components, with parents having to pass data to childs and even nested components that are further away. 

Let’s imagine a scenario where we have three tiers of downward components. The parent component has the data we wish to pass, and the third level of the component tree is deeply nested after it, being the ultimate destination for the data. Props would allow us to pass our data to this point, but at the sacrifice of the clarity and simplicity of our code. Let’s see if we can accomplish this without compromising either.

In order to follow this tutorial, we recommend you create your own Vue app and code along. Let’s get started!

Passing data with the provide() function

The function we will use to specify the data we wish to be sent down to a child component is the provide API.

The provide function is first explicitly imported from Vue before being used inside our script setup component. When provide() is called, we may define each of its properties thanks to this syntax.

Two parameters are accepted by the provide function:

  • The name of the property (a string).
  • The payload of the property (a string or an object that might contain several different values).

Let’s take a look:

<!-- Parent component -->
<script setup>
import { provide } from 'vue'
import Website from './Website.vue

provide('website', 'Upmostly')
provide('websiteData', {
  URL: 'https://upmostly.com/',
  meta: 'Learn React and JavaScript'
})
</script>

We call the provide function inside the setup method after importing it in the code above. In our example, the parameters for the first provide function are then passed with the name “website” and the value “Upmostly”.

On the other hand, we pass an object with the URL and meta description values inside and name its property “websiteData” for the second provide function.

Calling our data with the inject API

In contrast to this first part of the exercise, in this second part we will use the inject API function to get the information from our provider component.

We must import the inject API from Vue just like we did with the provide function. This enables us to use and call it from anywhere in our component.

As was the case with provide(), the inject function requires the following two inputs:

  • The name of the injectable property.
  • A default setting, this second parameter being optional.

Let’s examine the following code:

<!-- src/components/Website.vue -->
<script setup>
import { inject } from 'vue'

const websiteName = inject('website', 'Wikipedia');
const websiteData = inject('websiteData');

</script>

The inject function is first imported into our Website component. The websiteName variable is then set to the first provide() function, which has the property “website,” inside of our setup function. Additionally, we offer “Wikipedia” as an optional default backup value.

Then, the userGeoLocation variable is given the second supply function, which has the property name “websiteData”. As we’re using the Script Setup syntax, we are now free to utilize their values wherever we like across the Website component.

Can we make the provide/inject pair reactive?

As of today, the provide/inject combo is not reactive right out of the box. However, by utilizing either the ref or reactive function offered by the Composition API, we can very simply make the pair reactive.

As always, prior to calling the ref or reactive function, we must import them from Vue. We’ll save the provide() function in a variable and set its parameters to the value(s) we wish to give to the selected child component. 

As a result, the MyMarker component will now be updated whenever either property is changed! As you can see, the process is quite easy:

<!-- Parent component -->

<script setup>
import { provide, reactive, ref } from 'vue'
import MyMarker from './MyMarker.vue

const websiteName = ref('Upmostly');
const websiteData = reactive({
  URL: 'https://upmostly.com/',
  meta: 'Learn React and JavaScript'
});

provide('websiteName', websiteName);
provide('websiteData', websiteData);
  }
}
</script>

Should you use provide/inject instead of a State Manager?

As you probably already know, state managers like Pinia or Vuex are huge in the front end web development world. However, wouldn’t the provide/inject functionality we’ve just seen replace them inside Vue 3?

As it turns out, both tools have their place and can be quite useful in different contexts. In general, if we only need to pass data down several levels, we won’t need a tool like Pinia and can get away with using only provide/inject.

On the other hand, if we want to have data that’s globally accessible, a state manager will be extremely useful in most cases.

We hope you’ve enjoyed this tutorial! If you have any questions, let us know in the comments.

👋 Hey, I'm Alejandro Rodríguez
Hey there! I'm a front end developer from Spain and a web dev teacher at Ironhack. I've been writing for more than 7 years as a side project, and I love to mix both disciplines whenever I can. Besides working, I'm also passionate about travelling (often with my laptop as a digital nomad) and water sports. What could be better than writing about code in a Caribbean beach, or from a coworking space in an european city?

💬 Leave a comment

Your email address will not be published. Required fields are marked *

We will never share your email with anyone else.