Creating Team Pinia Store0:00
Okay, so check this out. In this episode, we're going to switch over to using a dedicated Pina store for our team. And when we do that, we're going to obliterate that entire prop drilling problem that we've been running into over the last few episodes. So check this out. Let's get going. Now, the first step, of course, is to create our store. So let's add within the stores directory a file called teamstore.js. And like we've learned, we need to define a new store. So we will import that from Pina, and I'll shorten this.
And like we've learned, we need to define a new store. So we will import that from Pinia, and I'll shorten this. And the name will be team. And here is our object. And again, this is where we would declare the state and the actions and the getters. So at the moment, I'm going to keep doing state like this. But in a little bit, we're going to switch over to using an arrow function. But yeah, you can imagine we need the team's name. We need the team's spots. I think that's what we called it.
Wiring Store Into View0:55
We need the team's spots. I think that's what we called it. And then we need an array of the team members. Okay, so let's name that. And again, using conventions, we would call it useTeamStore. And I will export that. All right, next up in TeamView, we will start by importing it. Import useTeamStore from our team store. And then I just need to call that function. And we'll save the results to a variable called team, which is then instantly available in
And then I just need to call that function. And we'll save the results to a variable called team, which is then instantly available in our template. And again, because we're using script setup. Okay, so let's comment out where we import the team.json file just for a little bit. And we'll figure out where that logic needs to go. Okay, so if I switch to the browser, we give it a refresh. And yeah, we don't get anything. Everything's kind of worked here. Okay, so let's go into the View tab.
Seeding Store With Action2:05
I'll switch back to our team store. And yeah, think about it. In real life, often you need to seed your store. So maybe that's coming from a database or an API call, or again, in our case, just a simple team.json static file. So where and how exactly do we do that? Let me show you. Let's create a new action here. And remember, an action is just a method. And yeah, common conventions might be init.
And remember, an action is just a method. And yeah, common conventions might be init. I often see that. Some people call it handle. Some people call it fill. Some people call it seed. It just sort of depends. But fill is pretty common, so I will stick with that. And yeah, here is where we can do really whatever we want to fill the initial state. So again, it could be an AJAX call, or it could be a simple import of our team.json.
And yeah, here is where we can do really whatever we want to fill the initial state. So again, it could be an AJAX call, or it could be a simple import of our team.json file. Let's do that now. And we'll do it dynamically. I can say import team.json. And then with the results, let's simply log it to the console, and we'll take a look. Now, of course, though, if we run this in the browser, we're not going to see anything because we haven't yet called the fill method. Okay, let's do that now within TeamView.
because we haven't yet called the fill method. Okay, let's do that now within TeamView. So we import our store, and then we call team.fill. So yeah, notice how we can interact with any action as if it was declared at the top level. And the same, of course, is true for your state or your getters. Okay, so now let's think about it. We import our team's store, we initialize it, and then we call this fill method. The fill method will import from our team.json file, and then all it's going to do is log the results to the console. So if I come back and give this a refresh, let's go to the console.
the results to the console. So if I come back and give this a refresh, let's go to the console. And sure enough, here's what we get in response. So we really want the default export, so we'll do .default. And yeah, if we come back and give it another load, sure enough, I can see the data that was returned from that JSON file. Okay, so now the next step is, how do we update the state using what was returned here? Well, I could do something like this. First, I could cache r.default. And then I could say, well, this.name equals data.name.
Updating State From JSON4:43
Now we see our team members again. And if we have a look at the PNU tab, sure enough, it's now populated with all the data we care about. Okay, so that would be one option. Another option would be to use the patch method, like this, this.$patch. Think of this as a condensed way to update multiple state properties at once. So for example, I could say name is data.name, spots is data.spots, and members is data.members. It's just a slightly different way to go about it. So I could get rid of this. And yeah, if I come back and refresh, we get the exact same thing.
So we could get rid of all of this and then clean that up. And yeah, let's give it a shot. We refresh and that works as well. Okay, so I'm just showing you some different ways that you can go about this. And in fact, one last thing, your actions can be asynchronous if they need to. So for example, if I want to declare this as an async function, then I could tweak this. I could then say, await for this import to complete. And that removes the need for the then call. So I would do something like this. Let response equals await import.
So I would do something like this. Let response equals await import. And yeah, that would be an option as well. Switch back, give it a refresh, and it still works. Very cool. And actually, one big benefit to this approach is we delay the importing of our team.json file until the very last minute. So for example, imagine you're browsing the site, you go to the home page or the about page or the contact page. In that entire process, you are not importing team.json.
page or the contact page. In that entire process, you are not importing team.json. You only do so when the user visits the team page. And at that point, we set up our team store, and then we call the fill method, which dynamically imports that file on the fly. So that's a big win to this approach. All right. So let's switch back. Our team store is looking pretty good. I can now delete this line at the top entirely.
Replacing Prop Drilling Usage7:22
Now we just have to replace it by importing the teamStore wherever we need to access it. Same thing. Import, use teamStore. And don't forget, these will be treated as singletons. So it's not like I'm initializing a new instance every time I import this. Use teamStore. OK. So I will copy this. And let's switch to the header where we need it. And then teamMembers, I'll paste this in.
And let's switch to the header where we need it. And then team members, I'll paste this in. And then fix it like so. And I think that should do it. So now if I switch back and I give this a refresh, yeah, everything's working exactly the way it did before. But now we are leveraging a dedicated Pinia store for our team. And of course, we can manipulate this on the fly. So for example, if we were to set a timeout to simulate some kind of action, maybe after two seconds, I could say team.spots.
Then here I could say this.spots equals spots. Yeah, that would be an option as well. So now I would just say team.grow. And this time we're going to grow it to 25 spots. Give it a shot. Refresh. One, two. And it develops from five to 25 spots. Okay, so now the last thing we should do is set up a getter. And remember, a getter is just the pinyin version of a computed property.
Adding Getter and State Style9:15
Okay, so now the last thing we should do is set up a getter. And remember, a getter is just the pinyin version of a computed property. It's the same thing. So yeah, you'll remember, where did we declare this? There's a handful of places where we have logic like this, where we calculate how many remaining spots there are on the team. That seems like a good use case for a getter. So let's do that now. So I'm here at the bottom, getters, and we could say remainingSpots or spotsRemaining. And what is the logic here?
So I'm here at the bottom, getters, and we could say remainingSpots or spotsRemaining. And what is the logic here? Take the total number of members and subtract that from the spots available. So if there are five spots and we have three members on the team, then there are two spotsRemaining. Okay, we have our getter. Let's switch back and use it right here. Switch to team.spotsRemaining. Okay, anywhere else? No.
Okay, anywhere else? No. What about the footer? That looks fine. What about the teamMembers? I thought we used it in more than one place. What about this one right here? We show a message to the user if there are no spots remaining. So why don't we say if not team.spotsRemaining? Okay, and then finally teamMember, I think that's probably fine.
So why don't we say if not team.spotsRemaining. Okay, and then finally teamMember, I think that's probably fine. Yeah, maybe right here as well. If there are not any team.spotsRemaining. And I think that is everywhere. Okay, so cross your fingers. Yes, I see that message. But then when we have that timeout that upgrades the team to 25 spots, it disappears. We update it there. Yeah, everything seems to be working just the way we'd expect.
We update it there. Yeah, everything seems to be working just the way we'd expect. But now we've refactored everything to a nice and clean teamStore. So the final thing I'm going to show you right here is how we declare the state. So often if you're reading documentation or tutorials, you might instead see them declare it with an arrow function. Now the reason why they do this is it provides some better TypeScript support. In our case, we're not using TypeScript, so it doesn't really matter. But again, it's probably best to get in the habit of this. So you may see people structure it like this.
But again, it's probably best to get in the habit of this. So you may see people structure it like this. Or if you want to do it inline like this, well, just remember a single line arrow function that needs to return an object. You must wrap that within parentheses, and that should do the trick. So again, this is a very common approach for declaring your state. And to tell you the truth, it's almost always the approach that I take. So I'd recommend it. All right, that'll do it for this video. Really good work.
