Remix Fundamentals

Errors Solution

Kent C. Dodds

Kent C. Dodds

Professional Trainer
Remix Fundamentals

Check out a free preview of the full Remix Fundamentals course

The "Errors Solution" Lesson is part of the full, Remix Fundamentals course featured in this preview video. Here's what you'd learn in this lesson:

Kent walks through the solution to the errors exercise. A student's question regarding if catch boundaries are for server-side while error boundaries are for client-side is also covered in this segment.


Transcript from the "Errors Solution" Lesson

>> So let us do exercise eight together. We are going to create this file. I am going to start with this one. And we will go to app routes posts. But before I create that file, first I just want to call out the fact that what we are doing is actually very similar to what we did with the admin route.

So where we have an admin TSX, that's our parent route. And then the admin folder holds all of our child routes. Well, right now we have a post directory that has child routes, but their children have nothing because we don't have a post TSX. And so what we're getting is actually kind of the default.

So this is basically what the default is. It's just an outlet, a component that renders an outlet. You won't see that in the dev tools that's just like how functionally equivalent default route so we're going to create that but first I want to demonstrate the problem that we're solving.

Thing and the problem that we're solving is if I am on the index route for instance and I say some runtime error which of course, TypeScript would protect me from but if we had Had that situation or anything yet gonna get this this is built into remix and it just shows you all that nonsense and it's like that is not a great user experience.

So our objective is to just make something that's more custom, something that's a better user experience for our use case. Okay, so that is what we're trying to accomplish. So let's make the parent route posts dot TSX and we're actually gonna grab the default. So we have functionally changed nothing everything is functioning exactly as it was before and we just now have an additional route and because we have this route now We can export a function called an error boundary, this will get a prompt called error.

And that error will be of type error. And now we can say, Let's console dot error, the error so we can look at it you might like send this off to a logging service or something Or potentially and yeah, we'll just return I do in fact we actually have this error fallback component that makes things look nice and inside of here we can say something went wrong.

If you get to this error boundary, it's unlikely that the error message is gonna be something that's useful to show to the user because it'll probably be, like, cannot read title of undefined or something like that, that just is not very useful. So I typically in my air boundaries, I will not show the error message to the user because most the time.

It won't make sense to them unless my users or developers in which case it actually might be quite quite helpful for them to say yeah, I got this thing. Okay, so with that, now we get snap something went wrong, a little bit nicer user experience you can make this you know if you want koala with a tear running down inside whatever so that is an error boundary.

That's the entire thing. And now you just slap these wherever you want them to go. So something that might be a little bit more obvious why this is actually a pretty nice convention is if we have an error in our admin section so if I were to say, when loading save law right here.

And then come over to my admin and go to a particular post. We're gonna get, snap something went wrong. So interesting thing is that these error boundaries will bubble though it remix says there was an error. Is there an error boundary at my route? No, there's not error boundary there.

No, and we'll just keep going up until we get to that post Arab boundary that I just put. Put there, okay? But if we wanna make an even better user experience, then we can put an error boundary right here, potentially have it be a little bit more specific so we could say something went wrong loading.

This post and now we have an air boundary, that's more Isolated and contextual for that area of the app. And so actually what might be kind of interesting is if we say, up here, this is what I was talking about earlier, so we have to say params.slug, Then we blow up.

And then I come down here and it all still works. So the users like hey, for some reason, I can't get my first post. They call up support. They say, my first post isn't working. The rest of them are fine. It's just my first post. I don't know why my first post, and then they report it to us and be like, yeah, I've totally forgot I was just doing a demo.

And now we'll delete that. [LAUGH] Right? So that is everything with arrow branches. The last thing that we had here was just to put one right there,but that is the basic. Idea of error boundaries just allows you to have something that's contextual, you do get access to the error and if you find that useful you can send that off to reporting or whatever but yeah render whatever you see fit.

For that error. I mentioned earlier when we were talking about this, that this also does work on the server render, which is cool and it works inside of our loader, not just our React components. So pretty resilient. The one thing or some areas where it will not work is some of your code that's running outside of the call stack of Remix.

So events use effects callbacks of various varieties that are outside of what remix is doing those will not be remix is not able to handle those. Is just by nature of how JavaScript works. But yeah, most everything else should work. Sweet. Okay, then let's do catch boundaries. So, error boundaries are intended for catching errors that are unexpected.

But if I go to my first posts, that's not an unexpected error. I can actually anticipate that that's probably pretty likely to happen and in fact we have a convention for that on the web and that is status code 404 not found we're looking for something didn't find it So what we are going to do is just make sure yeah, we're an admin slug.

If the post is not found, instead of just throwing an error saying, hey, post wasn't found. What we want to do is we want to send a response to say, hey, the post wasn't found and, and then render something that says, hey, there's no post by that name.

So what we're going to do is we'll say if there's not a post, then we don't wanna execute the rest of this code. We do still want to throw so that it doesn't continue and return this JSON. I suppose we could return JSON here that says, post is null or not found or whatever you want to do and then.

And branch on that inside of our post admin component and say, hey, if it was said not found and render this component instead, that seems like a lot of work. I don't want to do that. Instead, what I want to do is I just want to have some mechanism that says, happy path is over here and it's beautiful.

And there's green grass and gardens and flowers in this awesome and then sad path is over here, and they're separate. So and that's what the error boundary does. We have a catch boundary for this as well. So we're going to throw a new response. And I'll just say not found with a status of 404.

We want that status code that's important. Browsers behave differently. Search engines behave differently. All of that. It is important that you have proper status codes. Did for a long time everything was a 200 for me and that is not the way it is web apps for all force they matter so we're gonna send that status but we're throwing Remix's the one calling our loader, and so remix is going to catch this thread response.

So it catches anything and says, what is this thing that was thrown? Was it a response? It was, great. Then I'm going to go down this code path. And this code path says I'm going to look for the closest catch boundary so we're going to export a function called a catch boundary this one has a slightly different API this one you get a cut that's what we call it it's kind of a weird name and we may change it.

But use catch is a hook that you're going to use from remix on react and this caught thing is going to be the response that we threw. Okay? So we threw a response. We get that response with use catch and I'm also going to get the Params for my error message.

So use Params. And then I'm going to say if the current response status is 404 then I'm going to return an error fallback that says no post found. But found with the slug. Params. That's like, If it's not a status 404, then somebody else somewhere through a response and I don't recognize it, so I'm not gonna deal with it.

What I'll do instead is I'll just throw an error. It says unhandled response status, code status. And guess where that's gonna go? Right there. So I can deal with 404, but you throw me a 403. I have no idea what to do with that. So I'm going to just send it over here.

Cool, so now I come over here snap no posts found with my posts my thing yep the first post cool And that will client side render too so if you have a link that goes to 404 it will go over there it will not do like a full page refresh or anything it'll navigate over there and it'll render.

Under the catch boundary and the data response. So the request for the data will be a 404. You will get a 404 for that response and it will end up in the cache boundary. Cool, sweet, There's our 404 It matters folks it matters, okay and then of course we apply this the same thing to.

Or other route here. And then if you wanted to reuse this, how do you reuse components? You make a component and you use it again. So if you really wanted to reduce duplication and stuff you could totally make it like the master catch boundary that handles all the The different status codes if you want it to do that.

Okay, great. Any questions about exercise eight and error and catch boundaries?
>> So error boundary is for unexpected errors while catch boundary is for errors you know how to handle?
>> Yes, exactly. And actually somebody did ask during the exercise Time. Whether you should throw inside of your models.

So in here we could say, yeah, if we say get post. Here's my post await. And then if not post then you could throw in new response not found status four four otherwise return the post, so now this get post will always return the post you could do it this way.

I would not, I prefer to keep my models just like leave that to just regular JavaScript things. No semantically meaningful framework stuff in here but to each their own, I'm not going to. I tell you what to do I'm not your mom but yeah I would not do this.

I prefer to and part of the reason for that is what if this get. Post throw like there's a another way for this to throw an error now in your loader you have to do a try catch and you have to do a check was this a response then re throw that otherwise I gotta do my stuff like what nonsense I don't want to do that.

>> So no I wouldn't do it here are catch boundaries then for server side loader action logic while error boundaries are for client side.
>> No so error boundaries work for server side as well. It really comes down to unexpected errors where you say markdown dot 2 upper case All right, so maybe Markdown is not a string, or maybe it's no at this point error boundary.

So you did not expect that to happen. You messed up your code. That's an error boundary. Whereas the post does not exist. Yeah, clearly that's possible. I want to handle that case that I can expect.

Learn Straight from the Experts Who Shape the Modern Web

  • In-depth Courses
  • Industry Leading Experts
  • Learning Paths
  • Live Interactive Workshops
Get Unlimited Access Now