Creating First Pinia Plugin0:05
In the previous lesson, we added a nice dose notification whenever we add or delete the product from the cart. We added this logic inside our abdo view file, but actually there's a better way using pina plugins. Let's create our first PIA plugin together. Let's call it dosePlugin. In the directory plugins in here, we'll export the function. The function receives a context more on that later. And for now, let's say console.log in it plugin at let's log or context open up main.js,
And for now, let's say console.log in it plugin at let's log or context open up main.js, and in here we'll instruct PIA to use plugin. Let's say PIA use, we'll say toast plugin. And make sure you import the plugin. If you open up a project and take a look at a console, we'll see plugin gets initialized a few times once for every store we have. And this is by design.
Moving Toast Logic0:58
for every store we have. And this is by design. PIA Plugins apply globally on every store. Let's open up app view and we can copy our code we wrote in our previous lesson. Let's clean this up. And there we go. Let's open up our toast plugin. And we can actually paste our code here. We have to do a few modifications instead of card store, we'll say context store.
Refactoring Plugin API1:15
We have to do a few modifications instead of CardStore, we'll say ContextStore. And when we test or post notifications, everything still works. Great. Now this feels a bit dirty because remember, we're subscribing to every store and checking on the name of the action in here. This is pretty inefficient. So let's refactor things a bit. Let's actually get rid of this entire function and replace it with Context.
Let's actually get rid of this entire function and replace it with context. Store toast. success equals we'll get a message. I will say toastSuccess message. Let's do the same for toastError. We get a message and an action. And in here we'll say error and action. Then open up our cardStore. Let's update our incrementProduct action first. At the bottom, we want to say something like this.
Let's update our incrementProduct action first. At the bottom, we want to say something like this to toast success. I will say productTitle, add it to cart. But remember, our cartStore is actually a setupStore, and this means we cannot use this inside of an action. Instead, we have to say use cartStore and we'll call ToastSuccess on this instance. Let's do the same for removeProduct. Let's say use cartStore will call ToastError.
Let's do the same for removeProduct. Let's say use CardStore will call Toast error. We'll say productTitle removed from cart, and we'll pass in our action with a label of undo. And when we click on it, we'll restore the line with our product. When we test our app, everything should still work as expected, we can see our pasta being added to the cart with a nice toast notification. And then when we remove the pasta,
Exposing Styled Toast Helper2:58
with a nice toast notification. And then when we remove the pasta, we'll get our toast notification that the pasta has been removed with our undue action. And that's great. Our peanut plugin in its current form doesn't really add much value over simply importing toast in our stores. So let's improve this a bit. We'll expose toast to our stores as follows. We'll say Context store toast prefixed with a $ sign.
We'll expose toast to our stores as follows. We'll say Context store toast prefixed with a dollar sign equals message. And let's add some data. We'll say toastMessage with our data. And for consistency, let's set the duration globally to three seconds. And maybe let's modify the size of the title as follows Title, let's say text-lg. Then let's update our toastSuccess,
Title, let's say text-lg. Then let's update our toastSuccess, and we'll call this method. Instead, we'll say contact.store. Toast will pause our message and our type is success. We'll do the same for our error. We'll say type error, and we'll pause in our action. And I need to add our error function, obviously. And now when we call the toastSuccess or toastError function,
Using Persisted State Plugin4:12
And now when we call the Toast::success or Toast::error function, we'll see a consistent style being applied to the toast. And here we start to see some value being added from our plugin. There are a whole bunch of pre-made plugins available for Pina. For example, Pina plugin, persistedState, which is a plugin to persist the state of our store. We implemented this logic or cells,
to persist the state of our store. We implemented this logic or cells, but we can make our life a bit easier by using this plugin. Instead to start, let's edit Using our package manager. We'll say npm install vue-plugin-persistedstate. Next, open up main.js. We'll say Vue.use(pluginPersistedState), and don't forget to import it. Next we can open up card.js. We can find our watcher.
Next we can open up cardo.js. We can find our watcher and we can actually get rid of this entire function. And we can also get rid of the loading of our card from localStorage as follows, let's clean up our imports and then all the way to the bottom, we can pass in another parameter to our setupStore, which are the options. And let's say persist through
which are the options. And let's say persist through and automatically where we put items in the card and refresh the page. The plugin will take care of loading the card from localStorage back into the state. And if you open up our localStorage in the dev tools, we can see our card key. With the value of our entire card being persisted, we can even jump into our productStore,
With the value of our entire card being persisted, we can even jump into our product store, which is an option store, and we can say persist true. And when we reload the page, we'll first be greeted by a spinner, but then when we reload again, we won't see the spinner because the products are persisted into our local storage. But there's a big caveat here because we simply say, persist through everything in the state or products or loading,
because we simply say, persist through everything in the state or products or loading, and our debtLoadState will be persisted and reloaded from localStorage. To mitigate this, we have to update or persist through into an object, we'll say enabled through. And we can pick or state, for example, our products and let's add a new prop, caningInBackground, which we will add here.
and let's add a new prop, caningInBackground, which we will add here. We'll initialize it to false, and we need to set this value to true after we fetch the products. So we'll say caningInBackground = true. And maybe let's move this patch call in here. And when we have an error, let's actually patch and set loading to false. There we go.
and download through and loading. False. There we go. And let's say we want to show our spinner if we can not sync in the background. There we go. So now when we refresh, we'll first see a spinner, and then every time we refresh after that, we won't see a spinner, but the products are still being updated in the background. For good measure, we can also force to revalidate the products every 24 hours.
Revalidating Persisted Data6:59
For good measure, we can also force to revalidate the products every 24 hours. So let's add a new property to our state, we'll say updatedAt, let's initialize it to null, let's also persist this. We'll say updatedAt then maybe we fetched our products. We'll say updatedAt is now. And in here we'll check if the delta is bigger than let's say something like 24 hours. We will force the user to sit through a loading state.
say something like 24 hours. We will force the User to sit through a loading state and we can do the calculation as follows. We'll say const delta in milliseconds equals date. Now minus this updatedAt, we'll say delta in seconds equals delta in milliseconds divided by 1000. And that's maybe rounded. And in here we'll say if we cannot sync in the background or the delta in seconds
And in here we'll say if we cannot sync in the background or the delta in seconds is bigger than let's say five. To test quickly, we have to present the user with a loading state. So now when we refresh, we'll see our loading state. And when we refresh fast enough, we won't see a loading state unless we wait for over five seconds. And now we'll see a loading state again.
unless we wait for over five seconds. And now we'll see a loading state again. Let's update the five seconds into something more sensible, like an hour maybe. And this is a pretty common technique when working with persistent data where we have fresh data in our storage. We show this immediately while we fetch new data in the background. And if the data is too old or stale, we show a spinner
new data in the background. And if the data is too old or stale, we show a spinner and don't preload the persistent product. However, that we can conclude this lesson in which we took a deep dive into PIA plugins. We started by creating our own plugin to display toast messages, and we refactored our own persisting logic with PIA persisted state. The most important takeaway from this lesson is
with PIA persisted state. The most important takeaway from this lesson is that PIA plugins are always scoped globally and made available for every store. Let's move on to the next lesson.
