Vue 3 Fundamentals State Management with Pinia Exercise
Transcript from the "State Management with Pinia Exercise" Lesson
>> So, for this exercise we'd like you to do is also get some hands on experience just like you do with the router. Go ahead and open up the Pinia docs for reference because once again, the docs are a great resource for helping to debug and learn more things about the library as you continue using it.
[00:00:13] Then, go ahead and install Pinia onto the cest-la-vue app and configure Vue to use it. Again, it should feel familiar based on what we just did with Vue router. Go ahead and then create a stores folder, and then go ahead and just create any kind of data store that you think makes sense for cest-la-vue.
[00:00:27] Then once you create your first store, try to add some state, getters or actions. And then finally go and call those things inside of your components. All right, so as always, if you have questions, for those watching online, please feel free to drop that in the chat. Let's go ahead and run through that.
[00:00:48] So, we're going to do this is let's go ahead and restart and this time we're going to go ahead to the cest-la-vue. And then we're going to install pinia, that's the first thing we're gonna do. Once you have that then I can go ahead and run dev. I can have that over here, which is great.
[00:01:06] Okay, that's working now. So, once you have Pina installed, what you gotta do is you gotta configure it. So, inside of, oops! I'm in the wrong folder, inside of cest-la-vue for main.js, we have here, this is where we're creating the Vue router. Let's then go ahead and find createPinia app functionality from pinia.
[00:01:27] So, as you can verify that, you can always check the autocomplete. I usually do autocomplete cuz it just prevents the one off typing errors that I have, which you've seen me do on this workshop. So, once we have that. Great we can then. Okay, we have a bunch of router stuff here let me just collapse that and then const pinia = createPinia().
[00:01:48] And we're gonna do app.use(pinia). All right, so, now that we have that enabled we can go ahead and create our first store. So, what we're gonna do here, inside of our components, it looks like, honestly, the user store makes the most sense. So, we can go ahead and do userStore.js.
[00:02:10] And so, we're gonna go ahead and import definePinia from pinia. And then we're gonna export our store, which is gonna be a const of useUserStore, and we'll call the define, not definePinia, my mistake, defineStore. We've already defined pinia at the app level now we're defining a specific store.
[00:02:32] The store gets what? It gets two arguments. One, what are we going to call the store? Again, keep it simple. I like to keep it whatever the file name is. So, it's userStore and then we get an option of what? We get the state which is a function that returns an object.
[00:02:46] We get the getters, and we have the actions. Okay. So, what we can do, if we take a look at our code is inside of our views inside of UserPage. You can see that we're doing quite a bit here as far as the data goes. Now, we're importing it currently from composables, so let's migrate that over, that's what we're gonna do in this particular one.
[00:03:08] So, inside of composables you'll see that userList is just a ref. Well, if that's the case, all we got to do here is to show you side by side in our userStore is add a userList and then just make it an array. And when we save that, now when we go inside of our user page, rather than importing the user list like this, what we're gonna do is we're gonna import the useUserStore from, and then this should be from stores/UserStore, just like that.
[00:03:43] And so again, let's just double check. I didn't get the one. Wait, nope. Export const useUserStore. That should be the right one. We'll find out just momentarily, okay. So, then we will set up the store by what? By calling our function. So, const userStore = useUserStore, and then we'll go ahead and save that.
[00:04:05] And that looks good. Okay good, now it's actually being fetched correctly, that's good. So, now that we have the userStore, we can get rid of this .value. No longer that, it's just userStore.userList, just like that. So, let's see if that actually worked. If we refresh, go to the user page, we'll see something is not working.
[00:04:24] Okay, why? Because guess what? We're looking at userStore.userList but inside of our template, you'll see that we're only referring to userList directly. So again, one of the things I like about the modular way is that it's very clear about where things are coming from. Now, for those who really care about destructuring making your code shorter, there are ways to do it.
[00:04:43] We're not gonna cover it right now because I do think using it out of the box like this has its advantages for being declarative and easy to understand. So, now that we save this, go ahead and take a look how that looks. And there we go, everything is showing up as expected.
[00:04:58] Now, the other things we can possibly do with this is we wanna go ahead and practice getting the getters, right? So, we were doing that on the HomePage, right here. So, we go on the App page, we have the ability to, wait, HomePage is here. We were looking at something called shortUserList.
[00:05:13] Well, all we can do instead is actually take this part and we can shorten the code by saying, okay we gonna take this calculation that we've done, and we're going to go to the userStore. And inside of our getters when they get a shortUserList, and we can use an arrow function for this, we'll get the state and it'll return state.userList, and we don't need the value.
[00:05:39] And this is the equivalent, of our computed property. Now that we have this in here, we can go back over to our homepage, which is right here. And we can actually now just remove this in its entirety. And we can then say instead of import userList, we're actually gonna import useUserStore.
[00:05:56] There you go, it's auto completed, fantastic. const userStore = useUserStore(), we are calling that. And now that this is available to us, we can then say, userStore.shortUserList, save. So, now we go back to the home. Oops, there we go, User Home. There we go, we have our shortlist.
[00:06:18] It's all kept in one place. Now one last thing before we wrap this up is that we need to actually verify how do we do actions, right? And so there was a great question earlier regarding the fact that if you look at userStore, you might be tempted to actually make this part some sort of asynchronous functionality, right?
[00:06:33] Like, I wanna fetch this, return it into this value. But when it comes to setting up state and managing that with composables, my recommendation for doing that is to always start with the initial empty state. That's where that's just start. And then later on when you're writing code, you'll have that or go ahead and override and populate it.
[00:06:49] But for now, always try to avoid the async stuff in here. Keep that just to the standard data types. However, what we can do though is inside of our actions, this is where we can write that fetch functionality. So, where is that currently living right now? My guess is it's on UserPage and sure enough look at this, async function fetch users.
[00:07:09] Let's just steal that entire thing away because it doesn't need to be here. So, let's grab that over into our userStore and drop that in. Now, this current syntax won't work, why? Because this is async function when you're defining it outside of an object. So, we need to do is actually make fetch users an async function like this and then let me try to save it.
[00:07:33] It'll format itself a little bit better, which is great. And then there we go. And then you can see we get the fetch here, we get this response, and then we get the response. But, rather than just return it in this particular case, because in this scenario, we're saying that this function is specific to the store.
[00:07:51] Actually, you know what? Take that back. We're gonna leave it like this. I'll show you the two ways on why. So, now we have the fetch users here, how are we gonna use it? Well, inside of our UserPage, we've gone ahead and we've said, okay, we have the user store, so what can we do?
[00:08:06] We can do userStore.fetchUsers. So, that should do the trick, user.userList = await userStore.ser stores fetch users, great. You'll see now that when we come over and refresh, everything is working still. Now, there's also value in case that you're like, well, I don't wanna have to manually fetch it.
[00:08:38] I wanna just whenever this is called, go ahead and update this. So, an alternative model, there's no right or wrong, it just depends on what your use case is. If you go inside of our UserPage, rather than having to call userList and assign it, we could do theoretically, if we just wanna call userStore.fetchUsers.
[00:08:57] That's all we wanna do. But if we do that, nothing's gonna happen, why? Because currently inside of our function, all we're doing is actually running, the, not that one userStore, great. You see here, we're only returning the response. We're actually not doing much with it. So, what we need to do instead is we need to refer to the userList.
[00:09:20] And so, unlike the getters, which gets the state in an arrow function, because the actions really do require the entire context of the app, this is where the this context comes back into play. So, we can go this.userList = response. So, now I want to refresh that you'll see everything appears, as we expect.
[00:09:40] And this is now, again it's tightly coupled but at the same time, this might be okay in this particular instance, because this is the global source. So, that's actually probably what we wanna do. When we fetch users we want the entire global state to update. So, basically I would say if you're writing or composing your functionality in this way, I think it does make sense that tightly coupled.
[00:09:59] In the event that fetch users has nothing to do with this and that's for whatever reason, it's a separate type of functionality. That's where it might make sense as a composable that you import into your store that does something entirely separate that then you can, better break up and compose your code.
[00:10:13] So, we're at the tail end of all this. Obviously, there's a lot more to cover as there's an entire world and ecosystem out there. So, some of the questions that have come up during this include things like what about things like design systems, component libraries? Well, you're just in luck because recently, Vuetify, which is the official library for doing view components with material design that has actually been released.
[00:10:37] So, if you go to veutify js, I want to say .org, nope. Ooh dot com, I messed up. This is, I think the most popular component library that the Vue ecosystem has when it comes to a really well maintained team that helps to make sure everything's kept up to date.
[00:10:57] As you can see here, they have wonderful documentation that if you come in here you can actually take a look at the different components. So, you know earlier I was showing someone the tables down here. So, you could take a look at something like a simple data table that automatically takes in data.
[00:11:11] It looks beautiful, you can sort it without doing any additional work. This is the kind of thing that you might wanna check out if you don't have time to build your own design library and that kind of thing. So, Vuetify highly recommended checking that out.