Sometimes you might have some tightly coupled components where we need to pass the data from a parent component to a child component nested several levels deep. We could do this by passing the data through the intermediate components as props. Let's see how that would look. Let's say that we wanted a single place to keep up with the currency type at the app component level.
Then we could pass it down to the yummy meal component as a prop. make sure the yummy meal component takes it as a prop and use it to create our pretty price. This works, but yummy meal is only one level deep. What if the price lived even deeper within the component tree?
To illustrate this, we can make a component called yummy meal price that is solely responsible for calculating the pretty display of the price and actually displaying it. Then, we'll extract all the things dealing with price from Yummy Meal into the Yummy Meal price component. First, I'll move the price pretty computed prop over to the new component, return it from setup, and make sure to have the computed function available. Then, I'll remove the return of the computed prop from the Yummy Meal component.
I'll replace the printout of the price pretty in the template. with the Yummy Meal price component and pass it the price as well as the currency symbol. Lastly, I'll remove the unused computed function and replace it with an import of the Yummy Meal price component, which means, of course, we'll need to register the Yummy Meal price component. I'll also need to make sure the Yummy Meal price component takes in the price and the currency symbol as props and to round it out.
Provide the price pretty in the template. If we check things out in the browser now, you can see that nothing has changed. We still have our list of meals with prices intact. Cool.
The problem with this is that we're passing the currency symbol through the yummy meal component, even though the yummy meal component really doesn't care a thing about it. Furthermore, what if we end up putting a component or two more between yummy meal and yummy meal price? we'd have to remember to pass the currency symbol down through each component. To solve this, we can use provide inject instead of using props.
In the composition API, this approach starts with, you guessed it, a utility function. view, we import the provide function from view. And then inside of the setup function, we can call it. provide takes two arguments.
The first is the name of the variable to inject. The second argument is the value of the variable to be injected. Now we can get rid of the currency symbol variable we had before and we no longer have to pass it to the yummy meal component. Nice!
This means yummy meal no longer has to take in the currency symbol as a prop or pass it on to the yummy meal price. Now we can pick up the currency symbol in the yummy meal price where we actually want it without yummy meal knowing a thing about it. To do that we'll first have to import the inject function. Then we can define a variable called currency symbol and use inject to define it.
Now when defining price pretty we can use the injected variable instead of the currency symbol from the props. If we check things out in the browser now, you'll see that our price still looks good. And looking in the View DevTools, you'll see that the Yummy Meal component no longer has to take in the currency symbol as a prop. Instead, it's available via a provided variable.
View also has direct access to the currency symbol as well, no matter how deeply nested it is. If we wanted to make an injected variable reactive, we'd of course have to use ref or the reactive function. Since currency symbol is a primitive, we would need to use ref. value, since we're now dealing with a reactive ref.
Lastly, let's make a way to update it so that we can see the reactivity in action. I'll create a select input. Give it the V model of our currency symbol and provide a couple different options. Lastly, I'll give it a label.
And we'll also have to return currency symbol from the setup function. That way it's available in the template. Sweet! Now we have a reactive variable provided by a parent component so that any child component can inject it into itself should it need it.
Best of all, we aren't having to pass around the currency symbol from component to component via props. One last question you might have with provide inject is what happens when a component injects a variable the root component doesn't provide? Well, let's try it. view.
Now in the browser, we get a broken page and an error in the console. we can mitigate the risk of the parent not providing the currency symbol by providing a default for the currency symbol and the yummy meal price component. Cool. In conclusion, the use case for Provide Inject isn't very realistic here.
For internationalization, you'd really want to use the Vue I18n plugin, and obviously just changing the currency without changing the dollar amount won't work in a real app. However, the functionality of Provide Inject is clear. You can use it whenever you need to provide data from a parent component to a deeply nested child component. This works for static data, reactive data, and even functions that you might wish to share.