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.