Shortlist delete bug0:00
We've sort of already started the refactoring of the shortlist component, but let's finish the migration to make it work with the Inertia data. All right, so as a very quick reminder here, I am logged in with Simon and I can like puppies and they will get added to the short list after a three second sleep. But if I try to delete one, it will look like it's working, but it'll not because it's actually trying
But if I try to delete one, it will look like it's working, but it'll not because it's actually trying to do the delete on the external API. So we're going to bring this functionality in-house now and that shouldn't take too much work because we've already got all the pieces that we need to make it work. All right, so let's open the short list component. And so it's already receiving the correct puppies, which are the Inertia puppies,
And so it's already receiving the correct puppies, which are the Inertia puppies, and we are checking if there's a logged in OAuth user to display the liked by filtering. So that makes sense and it's already working, but the part that is not working is this delete button here, where at the moment we are still doing the asynchronous call to the external API with a fetch request. And again, we are maintaining our pending state manually here with useState.
Using Inertia router.patch1:23
And again, we are maintaining our pending state manually here with useState. And so that's the part that we're going to refactor. Now, uh, it's going to feel quite similar to what we've done for the like toggle because this is essentially the same thing, but remember how we've used a link tag. I wanna show you that there's different ways to go about this in Inertia. So here, instead of completely deleting the onClick,
to go about this in Inertia. So here, instead of completely deleting the onclick, I will actually keep that for this time and have my own little function inside of here. Okay, so you've previously learned that with Inertia you can use a link tag and then set a method on it if you want to send a POST or PATCH request and the link is going to be turned into a button if this is not a GET request, well turns out that if you want you can also directly use
to be turned into a button if this is not a GET request, well turns out that if you want you can also directly use the Inertia router to achieve this. So here I can go router and you can see here I can import it from Inertia and then I'll be able to choose among a lot of things. But here I want again the patch. And so that's going to allow you to pass a URL and then some options and data. But we don't have any data to pass for the URL.
and then some options and data. But we don't have any data to pass for the URL. We can again use the Ziggy route and go puppies.like and pass the id. So this is very similar to what we've done in the like toggle. We send a request to the puppies.like route. And to refresh your memory one more time, in the PuppyController that we've created, we have a like method here.
in the PuppyController that we've created, we have a like method here. And so here this is the route that is called puppies.like, and then we pass the puppy as part of the route. Okay? And I believe that's all we've got to do to make it working. So let's try delete Ross from the short list. 1, 2, 3 seconds. And that worked, but once again it scrolled us to the top of the page.
Preserving scroll position3:06
And that worked, but once again it scrolled us to the top of the page. Alright, so let's see if we can fix that with the router patch. So the first argument is the URL. Then there is data that we don't have and then there are a set of options where I believe we can have the preserveScroll true option. So let's try that. The first argument here is the URL for the data.
So let's try that. The first argument here is the URL for the data. Uh, maybe we pass an empty object. And for the third argument now, which are the options, it looks like I have the preserveScroll option and let's set. That's too true. All right, and let's try one more time. I will scroll down this time and try to delete rex. And I feel like we need to remove the sleep function at this point, but as you can see, it has worked.
And I feel like we need to remove the sleep function at this point, but as you can see, it has worked. We have preserved the scroll position. However, unless I'm mistaken, I don't think that there is the equivalent of a data loading attribute like we had on the link tag. And so it's a little bit harder to do the pending state when using the router. Sure, you have methods like onStart and onFinish, which lets you hook to some timings.
Refactor with useForm4:02
Sure, you have methods like onStart and onFinish, which lets you hook to some timings and do some pending states manually. But I think we can either go back to the link tag, but I can also show you another approach, which is to use a little form and use the useForm helper from Inertia. So here we are going to replace this with a little form to show you the useForm helper. So at the top of the file here I will import
to show you the use form helper. So at the top of the file here I will import useForm from inertia-react, and then in the delete button, which is where we want a form, let's go const and destructure an empty object for now and call the useForm hook. So that's going to allow us to look at what's available inside. And you can see lots of useful things like a form.
to look at what's available inside. And you can see lots of useful things like a form cancellation, the form data form errors. But here what we interested in is a property called processing. You can see where this is going. Basically this processing from Inertia is going to replace the manual pending state here because it gives us the same value a processing that is either true or false, just like pending value was.
because it gives us the same value a processing that is either true or false, just like pending value was. And another thing that we want to grab from the form helper is the method that we are going to submit, which is here, patch. Alright, next we can wrap our button in a form tag. Let me put the closing tag after the closing button. And here on submit I'll do it directly in line. We are going to receive the event and then first prevent the default
We are going to receive the event and then first prevent the default to prevent the form from submitting so we can manually decide what to do. And what we want to do is just like we were doing here, we want to call the patch method. You can see it accepts two arguments, the URL and the options. So just like we were doing here, the URL is going to be the route named puppies like and we pass the puppy id.
So just like we were doing here, the URL is going to be the route named puppies and we pass the puppy id. And then in the options we are going to have preserveScroll set to true as well. So to recap to this point, our button is now wrapped in the form and when the form is submitted, we do the same patch request that we were doing on the button on click. So I can get rid of the onclick event here and maybe let's give a type of submit to our button.
So I can get rid of the unclick event here and maybe let's give a type of submit to our button so it submits the form. And the last thing that we can do is replace our manual pending state, this one with the processing from the useForm. So I will replace these two instances with processing. So when we submit the form, this should call this patch method, which is going to set the form in processing mode.
this should call this patch method, which is going to set the form in processing mode. The button is going to be disabled. The lotus circle should show until the response come back from the form submission. Let's go and try. But before I try, I want to get rid of the state that we are not using anywhere. And I also want to get rid of the setPuppies that we are not ever calling.
And I also want to get rid of the setPuppies that we are not ever calling. That means I can probably get rid of more stuff here, the setPuppies, which means that I can remove it here and on the type. And again, cleaning up a bunch of prop drilling and types drilling, which always feels nice. I think this is looking good now. So let's go and test our implementation of our useForm helper.
So let's go and test our implementation of our form helper. And so I need to add some puppies before we can do, and you know what, I'm going to remove the sleep or change it to one second maybe. So PuppyController. And here the sleep is going to be only one second because we get the idea. That should still be enough time to show us the loading spinner.
That should still be enough time to show us the loading spinner. And I'm gonna like three puppies. Great. All right. And now let's go and try to delete Luna. And I'm expecting to see a loading spinner while the form is in processing mode. All right, ready? 3, 2, 1, delete spinny spinny. And it's gone. Delete Rex, delete Bella. And it's all working really nicely. You know what, doing this implementation
Disable like during requests8:06
And it's all working really nicely. You know what, doing this implementation of the useForm helper made me realize something particularly where we set the button to disabled using the processing state that the useForm helper is giving us. I think that in the like toggle, we haven't actually made the button disabled while it's spinning. So I think I could double, triple click
while it's spinning. So I think I could double, triple click and send multiple requests, which would not be great. Let's give it a try quickly. So I'm going to try to like Bella and then click on the like button a few more times while this is loading. Ready, click, click, click, click, click, click, click. Oops. Well we have bad news but also good news here.
Oops. Well we have bad news but also good news here. So the bad news is I was able to click multiple times on the like button and fire multiple requests while it was supposed to do the work. The good news however, is as you can see, all the requests that I've done here except the last have been canceled. So Inertia understood that I was trying to repeat the same uh, requests.
So Inertia understood that I was trying to repeat the same uh, requests and it canceled the request in favor of the next one, which is very nice because you have to do this manually typically, but it looks like Inertia is handling this for us. Now let me clear the network and we're going to compare this with the processing state. So click, click, click, click, click, click, click, and my last click has selected the image.
So click, click, click, click, click, click, click, and my last click has selected the image. And so you can see there was only ever one request that was sent through, which I think is much cleaner. So in hindsight, while our data loading, styling with CSS was pretty cool, I think we should go in the like toggle and also implement a little form and then use the processing state from the useForm helper to be able to properly disable the button while the
and then use the processing state from the useForm helper to be able to properly disable the button while the action is being performed. So let's do that real quick. I am in the LikeToggle component and I will import useForm from inertia-react. And here we will grab the processing and also patch from useForm like we did before. We're going to wrap everything in the form.
and also patch from use form like we did before. We're going to wrap everything in the form. Once again, let me paste the closing tag here. And so this is going to be back to be a button. So we will remove all three properties here that are link components properties, but let's give it a type of submit. Yes. Okay, now let's handle the disabled state. So if there is no user, we want it disabled and we wanna also check or processing.
So if there is no User, we want it disabled and we wanna also check or processing. So that should take care of while the form is processing. And here we're going to backpedal on our groupDataLoading attributes class. So I will show both by removing these classes here and here and here. Instead I will have again a turny. I think copilot got it right. I hope if it's processing, we have the lotusCircle,
I think copilot got it right. I hope if it's processing, we have the lotus circle, otherwise we have the heart that looks right to me. But I need to remove that. And I sure hope that it kept the same classes and didn't hallucinate something. This is looking. All right. All right, let's delete that. And so the last thing I need to do is handle the form submit with ub, submit. And so here once again, we're going to have the event.
submit with ub, submit. And so here once again, we're going to have the event and then events that prevents default. Uh, whoops. And let's verify that copilot did what I wanted. We patching the puppies like route, we pass the puppy ID and preserve scroll through. This sounds all okay to me. Let's go give it a try. I will clear the network tab and I will try to like Rex and click, click, click, click. Oops. I've clicked one more time after it had finished,
and click, click, click, click. Oops. I've clicked one more time after it had finished, but it looks like it's working. Let me show you one more time. I'll do three rapid, click, click, click, click, and stop. And only one has been recorded because the button was truly disabled. And really, if you want the proof in the pudding, I can inspect the element here and look at the button. And when I click, you will see the disabled
UI and code cleanup12:02
I can inspect the element here and look at the button. And when I click, you will see the disabled attribute and then it goes away. All right, I'm happy with this. We have a fully working shortList and puppiesList. Everything is working real nice. There is just this little issue here with the button not using the full height. Let me quickly fix that and we can wrap it up. Okay, so in the shortList we have this ally,
Let me quickly fix that and we can wrap it up. Okay, so in the short list we have this ally, which is the flex parent. The image has a height and width of 8, and then the delete button. So I guess the delete button should have a height of full to make sure that it's at least as high as the image. Ah, there you go. The height of full was on the button, but now we have a form tag. And so the form itself needs to have height.
but now we have a form tag. And so the form itself needs to have height of pool that should fix it. And yep, it's working nicely now. And so that's it for the design cleanup. And in terms of code cleanup, I think we can go in the puppies/index, which is our previous welcome route. And I can remove the setPuppies here that we are not passing anymore.
And I can remove the set puppies here that we are not passing anymore. And so the good news is the new puppy form is the last place where we make any use of that state that we will soon be able to get rid of. Alright, but before we tackle the new puppy form, I think we should take care of the search and the filtering next. So stay tuned for the next lesson where we are going to tackle exactly that.
So stay tuned for the next lesson where we are going to tackle exactly that.
