Do you ever find yourself passing a prop to a component, and then passing that same prop down to a child component, and then passing that same prop down yet again to the grandchild component? Well, if so, you're not alone. js. Likewise, you might find yourself doing the same thing except in the opposite direction with emits.
As far as I know, this doesn't have an official name, but maybe we could call it something like emit undrilling? emit juggling? I don't know. Either way, prop drilling and its emitting counterpart are both anti-patterns.
What is an anti-pattern? An anti-pattern is a practice you need to stay away from at all costs. Why? Well, because it makes your code less intuitive and harder to maintain.
So how can we avoid this anti-pattern known as prop drilling? In this video, let's take a look at a few different solutions. Number one, you could use provide inject. js feature that allows you to provide data at a higher level in the component tree and then access or inject that data somewhere deep down, no matter how many levels in the component tree you're nested.
In fact, this is exactly how Vue Router provides the router and route objects throughout your application. It provides them at the app component level and injects them into each individual component. That way, you don't have to accept a route or a router prop in every single one of your app's components. If you'd like the technical details on how to implement Provide Inject in your own apps, then you can check out this lesson in our View Three Composition API course entitled Using Provide Inject with the Composition API.
This is a really great course and provides you so much information on working with the Composition API. js. Another approach would be to utilize a global state management solution. Unlike providing Jack that stores the data at a higher level in the component tree, global state management allows us to keep up with the state outside of the component tree altogether.
And then we access that state in any component as we see fit. This can be as simple as a custom view composable. js documentation. Let's take a look at a quick example in some code.
Back in my project, I've created some files that look a lot like the diagram we saw earlier. view, I've got a piece of state, a reactive ref defined called count. And then inside the template, I'm passing count down as a prop to my component. Over in the components directory, if I open up my component, you'll see that I'm accepting the count prop, of course.
Then I'm displaying it in an li and passing it on down to my child component. I bet you can probably guess what my child component does. Yes, you got it. It does exactly the same thing.
Except now that it passes it on down to my grandchild component. Now, in your own projects, the prop drilling won't be nearly this apparent, but this provides us a good example. Over on the right-hand side, you can see what the output is now. And sure enough, if I update count at the app level, it does update in all of the different child components.
This is the desired behavior, but getting there is really messy. And if we forget to pass anything down between any of these components, things will break. So let's try implementing some global state management to do the exact same thing. Inside of my composables directory, I have a composable already written out called useCounter.
view before, and then I'm just returning. view, and let's use this count instead of the locally defined one. First, I'll import the composable, and then I'll extract count from it. Perfect.
vue. Whoops, except for I still need my component. OK, great. Now when I hit Count over in the browser, everything still works as expected.
However, we still haven't taken care of the actual prop drilling. Right, so let's remove all the different times where we've passed down count to the different components. view. Then inside of my child component, we no longer have to accept it as a prompt.
And we no longer have to pass it down. Where should count come from now, though, in my child component? view. Great.
I think we did skip my component, though. Yep, we did. So let's take care of defined props here. Don't pass it down.
and use the composable. And then we'll do likewise for the grandchild. Perfect. Over in the browser now, the output in the beginning is the same.
But if I click on the Count button, you'll notice that it's not working like it was before. none of the numbers in any of the components update. Why? Well, that's because we're calling useCounter in each of these different components separately.
And if you take a look at the definition of the composable, you'll notice that we set the count with inside of this function every time. And so every time useCounter is called inside an individual component, this count is set to zero for each of those different instances. So how do we make the count refer to a single instance of this count throughout all the different components? Well, the solution is actually super straightforward.
We just hoistCount outside of the function. Now, every time we call count that's returned from useCounter, it's referring to this count variable that's initialized a single time. In the browser now, if I give the page a refresh and click the button, sure enough, we get it working exactly as expected. Amazing.
And now we aren't having to pass the count prop down through multiple different levels of our component tree. Moreover, if we only needed the count state at the app level and deeply nested down at the grandchild level, we would only have to import the composable in those two places, not in every component in between. Creating a composable like this to manage global state isn't your only approach to global state management, though. js.
And it provides additional features over the approach we just saw, including first-class DevTools support and out-of-the-box server-side rendering support. If you'd like to know more about how to actually implement Pina, I highly recommend checking out our course, The Enjoyable Vue Store. it will walk you through all the exact steps that you need to get up and running with this amazing library. So there you have it.
Next time you find yourself prop drilling or emit juggling, stop and reach for a better solution like provide inject or global state management.