I was wondering if you have to handle, if, for example, if Prisma has an error, where do you handle that, and how do you transfer that back to client to be able to handle it, show it to the user? Yeah, totally. So you've got a couple of options, and in this exercise, we go into the action data response here for the errors for what the user entered. But you're talking about, like, what if I'm the one at fault? Like, I made a mistake. So we don't talk about error handling in this guide, but the JokesApp tutorial goes into both expected errors, like 401s, 404s, and things, and the unexpected errors. So, like, something blew up, I messed up. And the solution is, let's see, is to use this thing called an error boundary. So you export this function component that's an error boundary. It says, I messed up, sorry, whatever. And this is also gonna be nested in place of whatever thing it's wrapping. So, actually, on the Remix website at the very bottom is where we talk about errors. So you add the error boundary and in place of the component or that route, it's gonna render your error boundary. So that's how that works. It also bubbles up to the lowest common error boundary. So that's how you'd handle that. If you wanted to try and catch that error so that it doesn't blow up the whole thing and remove the form and stuff, because that is pretty reasonable, then you would just follow the same pattern here. You'd maybe do a try catch around that and then send back an error message that says, hey, sorry, I screwed up something, whatever. So, yeah, if you were like, yeah, my database is pretty unreliable or something like that, or in this case, we actually don't handle the case where the slug is unique. So if I tried right now to create a new post that has the same slug as another one, then that's gonna blow up something as well, and this is what I get without having an error boundary in place. Yeah, that would be a thing to probably check for. Perfect, yeah, that just drew a perfect line to your Epic React course that makes sense now, with the error boundary, yeah. Cool, thank you.
But I was wondering if you wanted to do something without a form, but you have a button that's an action, can you do it without a form? Because I guess Remix is following this old-school web model, like you say, where the state is managed through the form on the server and whatnot. I was just, yeah, wondering. If, for things that don't need a form, but you still want that same kind of behavior. Yeah, that's a great question. I was gonna show you in this, but I think I shipped it back to that. So let's run it locally so I can show you what I mean, or show you an example of this. So I'm gonna start the dev server, and it starts so fast. Have any of you noticed how fast the dev server starts? Isn't it great to have a dev server that starts really fast? I think it's great. Okay, so if we go to deposits, we're gonna see a little trash can icon right there. So it's like the button. And so I'm gonna click on that and it deletes it. That's a mutation, right? So how does that work? Well, as it so happens, this is just a form. So we still have a form, and we're just wrapping the button, or the trash can icon in a button, and that is the submit button. So you'd be surprised how many things can just be a form. And that's the way that we used to do it back in the early 2000s. So keep in mind, actually, that the method is still POST, even though we're actually deleting, because the browser only supports GET and POST. You can totally do DELETE here, it is supported, but that runs contrary to progressive enhancement because the browser doesn't support that. So we just do POST and then we handle that ourselves. But in any case, so that's how you do that if you have some visual thing. But your question leads me to another common question, which is what if I want to do a mutation that doesn't involve user interaction at all? So on my personal website, I've got on my blog, when you oh, looks like Red is in the lead. Huh, that's new, congratulations Red. When you go to one of my blog posts, if you read the whole thing, you scroll through the whole thing, then I count that and you're on the page for long enough, then I count that as read and that's what goes into the rankings for the different teams based on what team you're on. And also I keep track of how many reads there are total of weather or not you're logged in. And I don't want you to have to like click a little checkbox to say that you read it. So we need to do a mutation that happens without you actually doing anything. And so the way that I do that is with useFetcher. And so useFetcher has this, the ability to create forms for that particular fetcher, which we're doing for this delete button, but also the ability to say.submit. And that's what we saw earlier with the customer thing. Where's the customer and the resources here. So in here we say, hey, fetcher, I want you to submit so that you can actually do that sort of submission without any user interaction. So yes, your use case is handled.
Quick question, so in our example, we do a redirect after we finished creating the new post. Is that the reason why the list of posts is getting updated? If not, can you maybe quickly explain what is going on under the hood? Yeah, the reason we redirect is just because when a user is finished with their post, we just figure they don't want to make a new one, but maybe they do. So, you do not have to do a redirect for the UI to get updated. The reason the UI gets updated is when there's a successful mutation, Remix will automatically refetch all the data that's on the page, that's it. And so that's why you never have to think about keeping your data up to date. What would you return in place of that?