تماشای این درس نیاز به اشتراک حرفه‌ای دارد.

Sibling state problem0:05

In the previous lesson, we refactored our code to use, provide and inject. While this is a great solution for providing state to child components and deeper descendants, it's not suitable to share state with sibling components. Let's see how we can fix this. Using a composable, I added a view router to our example with an additional page. We now have two pages in our pages directory.

Adding Vue Router pages0:24

with an additional page. We now have two pages in our pages directory. We have our new checkout page and we have our homepage, which was previously our App component. The checkout page displays our Card component. It'll display a subtotal, our taxes and our total, but we'll worry about that later. In our main.js file, we initialize the view router by importing our router

In our main JS file, we initialize the view router by importing our router and saying create app with our app component, and then we will use our router. And in our app component, we simply display our view. If you take a look at our homepage, we'll see it still works as before, which is great. And now when we click the checkout button, we'll be able to go to the checkout page, but we get presented with a blank page.

Provide/inject limitation1:05

to go to the checkout page, but we get presented with a blank page and an error in the console. This error occurs because our checkout page is not a descendant of our homepage, which has been providing the card state up until now. One solution would be to join our state management from our Home component, go to our App component, say script, set up

to join our state management from our home component, go to our App component, say script, set up and paste our state management code here. And as you can see now, we're able to go to the checkout page and we'll see everything works as intended. This solution however isn't ideal because it forces us to manage all state in the top most component. And for larger apps, this quickly becomes unmanageable.

Creating cart composable1:41

to manage all state in the top most component. And for larger apps, this quickly becomes unmanageable. Let me show you a better way using composable. Composables are a great way to keep your state logic separate from your component. Let's create our composable in our src directory. We'll say composable cart.js by convention composable function names start with use. So let's export our useCart function. Let's add it into our App components, grab our cart state.

So let's export or use card function. Let's add into our app components, grab card, state and mutations and paste it inside of our composable. The card state needs to be managed outside of our function, so it's shared across all components. Instead of providing card state, we will move this inside of our function and we will say return, and we will return our card state. We will return or remove product increment product.

Replacing inject with composable2:32

and we will say return, and we will return our cardState. We will return or remove productIncrement product and decrementProduct mutation. At this point, our application is broken and we get an error in our console because we're using inject without apparent providing or state. Let's fix this. Starting with an FBar, the first thing we'll do is import useCart from composables/cart.

the first thing we'll do is import useCart from composables/cart. Next up, we'll get rid of inject and replace it with useCart instead. Now remember, because we return an object in our useCart function, we can destructure this object and take out everything we need. And in this case, that's only the cart. Next, let's do our productCart. We'll do the same thing. We'll import our composable.

Next, let's do our product cart. We'll do the same thing. We'll import useCart or composable. We'll remove, inject, and we replace inject cart with useCart. Next up our cart overlay. You know the drill import useCart from composables/cart and replace or inject cart with useCart. And let's clean up our import here. And our final component is our cart component. Import useCart from composables/cart.

Calculating subtotal, taxes, total3:44

And our final component is our cart component. Import usedCart from composableCart and we'll replace injectCart with usedCart. And lo and behold, our page works again with the state managed by a composable. Next, let's make sure our subtotal, our taxes and our total are calculated correctly for calculating the subtotal. We actually already did the work in a previous lesson, so we can take the logic from our cartOverlay

We actually already did the work in a previous lesson, so we can take the logic from our cart overlay and put it inside of our composable. So let's go to our cart overlay component and cut out the subtotal. Let's base this in our composable. And instead of returning a formatted string, let's simply return the number instead. And let's not forget to return our subtotal in our useCard function.

And let's not forget to return our subtotal in our useCard function. Now the subtotal is reusable and we can say subtotal here in our card overlay. And let's display a formatted string in our component. If everything went well, we should still see our subtotal being calculated correctly as before. Now let's go to our checkout page. We'll import our composable,

Now let's go to our checkout page. We'll import our composable, and then we can say const subtotal. We will destructure it equals useCart. Let's import our formatting function. And finally, let's replace our three dots with the subtotal. Now, when we go to the checkout page, we'll see our subtotal being calculated correctly. Next, let's create two more computed properties. We'll say const taxes equals computed.

Next, let's create two more computed properties. We'll say cons, taxes equals computed. We'll take our subtotal subtotal value times, and let's say the taxPercentage is 10% and it's always a good idea to round these numbers to two decimals. We can do that as follows, math.round we will paste our function, we will multiply it by a hundred, and then we will divide by 100.

or function, we will multiply it by a hundred, and then we will divide by 100. Next, let's create our Total. We'll say compute it again and we'll simply return our subtotal plus our taxes. And let's also round this number math.round. We'll say subtotal plus taxes times 100, and let's divide it by 100. Finally, let's return our Total and our taxes.

and let's divide it by 100. Finally, let's return our total and our taxes. In our checkout page, we'll import our total and our taxes. And here we can say format, taxes and format total. Now when we go to our checkout page, we'll see our taxes being calculated and our total also updates when using our card composable. We've effectively decoupled the state management from our components, allowing us

We've effectively decoupled the state management from our components, allowing us to use the state across our entire app by simply importing it as follows. And the best thing is we don't need to worry about parent-child relationships and our components are not responsible for managing state anymore. Our web shop, however, still has a big problem. The state is not persistent when we refresh the page,

Persisting cart to localStorage6:53

Our web shop, however, still has a big problem. The state is not persistent when we refresh the page, meaning we lose our entire cart on refresh. Let's mitigate this by writing the cards to the localStorage on every mutation. We can approach this in a few ways, but I like to create a watcher that will persist the cart to the localStorage on every modification. We'll start by importing watch from vue. Next we'll say watch, we'll return cart.

We'll start by importing watch from vue. Next we'll say watch, we'll return cart. Next up is our handler. We'll say localStorage.setItem cart. I will JSON.stringify our cart value because we need to react on quantity changes. We need to set the watcher up as a deep watcher and we can do so as follows, we'll say deep equals true. If you open up our application step and the dev tools and we navigate to localStorage,

If you open up our application step and the dev tools and we navigate to localStorage, we'll see a cart entry being updated every time we modify the state. All that's left for us to do is to load the persistent cart into our initial state and we can do so as follows, we'll say savedCart equals localStorage.getItem('cart'). And if we have a savedCart,

Clearing cart on order8:03

Get itemCart. And if we have a saved cart, we'll say cartValue equals savedCart. When we refresh the page, now the cart is being loaded from our local storage. Pretty neat. For good measure, let's add a clearCart function to our composable that clears the entire cart. Let's not forget to return this.

that clears the entire cart. Let's not forget to return this. And when we go to the checkout page and we press the confirmOrder button, we want to clear our entire cart and we can do so as follows, let's go to our checkout page. Let's find our button, and let's say addClick equals confirmOrder. Let's create our function here. Let's get our clearCart from our composable,

Let's create our function here. Let's get our clearCard from our composable, I will say alert. Thanks for ordering. We will clear our card. And finally, let's navigate back to our homepage. We need to import our router, composable, And let's say const router equals useRouter. Now when we press confirmOrder, we'll get our beautiful popup.

Now when we press confirm order, we'll get our beautiful popup. Our cart will be cleared, as you can see in the local storage, and we navigate back to our homepage. Awesome. Let's reflect on what we did. We refactor the use of provide and inject and use the composable instead. This composable can be imported from every component, so we don't need

Instead. This composable can be imported from every component, so we don't need to worry about providing the state to our child components. This composable also makes our code cleaner as we're able to separate the state logic from our components. Finally, we also made sure to persist the state in our localStorage and load it again when we revisit the page. Let's move on to the next lesson. I'll see you there.

Let's move on to the next lesson. I'll see you there.

دوست دارید گاهی خبرهای Laracasts را ایمیل کنیم؟