How to make your apps ERROR proof with Remix.run!

Video Statistics and Information

Video
Captions Word Cloud
Reddit Comments
Captions
hey guys welcome back to the channel you're  probably here because you love remix well me   too have you ever had a situation like this it's  Friday you've deployed a new version of your app   to production you're on your way back home and  you get a call from your boss and he tells you   production is down and you push code that throws  an error and that isn't handled yes no well in   either case let's talk about how to stop that from  happening in remix all right so before we get into   error handling if you haven't already I would  highly recommend you watch my routing video where   I go over how routing Works in remix and also all  the types of routes you can have in your remix   project and this is really important because you  need to understand how routing Works before you   can understand how error handling works so I'll  be adding a card on the top right or somewhere   and you'll be able to check out the video that I'm  talking about after you're done with that you come   back here and let's go over error handling if you  already know how routing works then perfect let's   go over the error handling now all right so the  first thing we need to understand is there are   two kinds of errors that can happen in remix the  first one is if you throw an error if you throw   an error what's going to happen is it's going to  break through your loaders and actions and end   up in the nearest error boundary so what this  means is if you have an error in products it's   going to throw and it's going to end up in the  nearest error boundary in this example here we   have no error boundaries which means this error  that was thrown in products is going to crash   your application and we really don't want that  to happen do we or maybe we do maybe we want our   users to suffer and another thing that's really  important to note here is that even if you throw   responses instead of Errors error boundaries are  going to catch them so what's important here is   to know that error boundaries catch both responses  and errors in your application originating either   from loaders or actions so you can use them for  both that it doesn't matter where the error or the   response originated from so if we want to protect  our dashboard here what we're going to do is we're   going to add an error boundary to the dashboard  and after that's added the dashboard is going to   be protected from throwing errors and responses  but everything under dashboard is also going to   be protected so this means that both the users  and the products are going to be protected so   this means if either users products or dashboard  throw an error or a response the error boundary   that's in the dashboard is going to catch that  and handle it so this means when you add an error   boundary to somewhere both the route that you've  added it to and all its children are protected   and if you might have guessed because we haven't  added anything to root if something goes bad in   the root this is going to crash and our user won't  see a fancy UI is going to see something really   horrible a blue screen of that but the browser  Edition so if we don't want that to happen we   can also add an error boundary to the root and  then everything in the application is protected   so if you add an error boundary to root TSX file  is going to be a generic one that handles your   whole application so that means if you even remove  the dashboard Arrow boundary from here it's still   going to protect your whole application because  you have one in the root and that's a great way   to segment your error boundaries so for example  if you have a generic one in root you can have   a more specific one in the dashboard and then you  can show a different UI to the user maybe display   some more specific information depending on on  his rooll or something like that it's really up   to you so the important thing to take away from  this is the fact that the root here protects   your whole application and that's a really neat  trick if you want to quickly protect your whole   application without going granular or wanting to  just prototype stuff and then add granular error   handling later on all right now that we have all  of this covered now let's go into code and let me   show you how this works in code how you can handle  errors what's going to be thrown and caught where   and some neat little tricks you can use to enhance  your error handling so to show you error handling   I'm going to be using my repository I used in  The View transition videos so the one with the   Pokemon and let's see how error handling works so  I'm here in my root TSX file and I want to add a   generic error Handler here so what I'm going to do  is I'm going to use remix Forge to insert an error   boundary here so remix Forge automatically adds  the Imports for use rout error and is Route error   response but both of these come from remix run  react so now that we have the aror boundary here   something I wanted to go over is the fact that  before remix version two we had two components   that were exported from each file one of them  was called error boundary and the other one was   called catch boundary so how they used to work  is if you threw an error you would end up in the   error boundary obviously and then you had another  catch boundary that caught responses so they were   fragmented into two and you either went into the  error boundary or the catch boundary so what the   remix team did with version two is they merged  both of them into the error boundary and how you   handle responses that were thrown you import is  Route error response here and then you check if   the error here is of that type and what's cool  about this is the error gets type narrowed into   the correct type so you have the data you have  the status and the status text here so you if   you through for example a 404 this would be a  status 404 and the data here would be whatever   you threw with your response so for example if  you threw a user here the data would be filled   with the user so if you want to do some granular  error handling for example show different screens   depending on the user you could throw user with  the data and then do more granual stuff here   for example if error. dat do user something do  something all right now that we have that covered   we know that the code here is the old catch  boundary which means if we go through this it   means the loaders or the reactions through an  error so this means if we are here there is an error and now let's actually change these two  so I'll make this have a background of yellow   500 and I know it's probably a horrible color  but I just want to show you what happens when   you throw something so I'll add something like  error status and er status text here and here   instead of the yellow we'll add background red  because it's an error and what we're going to   do here is we're going to just say error. [Music]  message and because the error is of type unknown   because it is you have no idea what was thrown  for now we'll just type this as any but what you   should do here is basically check if the error  has a message and then show it you can do that   with typescript cs for example you could do if  error instance of error then return the message   or actually we're just going to do that instead  and then here we're going to do something really   generic for example I don't know your app died  contact your developers and tell them to do a   better job all right and let's save this and let's  run the application now so this is version 2.4.1   and this is running on wheat but this doesn't  matter because if you're using anything over   two this is going to be identical and now let's  actually throw a response first here so what I'm   going to do here is I'm going to insert a loader  so I'm going to use remix Forge again here and   what I'm going to do here is I'm going to instead  of returning something I'm going to throw an error   so this is an error and we're going to save this  and as you can see it's through an error and now   let's go back to our browser and see what we have  all right now that we look at our browser here we   can see that what was rendered was only a div with  the class background red and the message this is   an error so this is what we threw in our loader  and this is what was rendered so if you might have   noticed this is not an HTML document and we only  rendered a div and this was on purpose just to   show you what happens so when you throw an error  and the error goes into the catch boundary the   catch boundary is going to replace whatever the  UI is on the current route with the error boundary   which means if you threw an error on the root of  your application it's going to replace your whole   layout with this so you need to be careful with  this because if we look at the console tab here   we can see that the error was thrown it was a 500  and because we replace the whole UI with this so   This validate Dom nesting error doesn't really  matter because this is not valid HTML this means   that we really need to be careful and handle our  errors in a way that the layout doesn't break so   let's go back to the code let's fix this so we can  see the whole HTML document instead all right as   we already said we need to render the whole layout  instead of the div here so what we're going to do   here is we're going to create a component that's  going to be reusable we're going to call it layout   and we're not going to export it because we only  want to use it here and co-pilot is being really   helpful here because this is the exact sign  signature I want and we're just going to let it   complete but this is not what I want what I want  here is this so I'm going to copy this and paste   it here and then what we're going to do is we'll  allow for everything here and we're going to throw   out Outlet here and we're going to replace it with  children and then we're going to wrap the app in   the layout whoops and then we're going to delete  every thing and just leave the outlet here and   in here what we're going to do is we're going to  replace all three of these with the layout we're   going to save this and also what we're going to  do is before we save this again is we're going   to move the scripts and the live reload into  the actual app itself because we don't want   this to be inside of the layout for the errors and  then we're going to save that and now if we head   into the browser you can see that we have our old  layout our scripts for The Styling are loaded and   here we don't have anything besides the get error  here so this means that when we were in the loader   for this route we got the status 500 and this got  logged here and if we look at the HTML here it's   correct and furthermore this here is our error  boundary so basically what we rendered here and   you can see it in the UI here so this is an error  is rendered so we've successfully defended our   whole application from errors and let's go back to  the code and let's throw a response now all right   so now we're back in the code and here instead  of throwing an error let's throw a response so   instead of throwing just a regular response I'm  going to throw a Json response and what I'm going   to do here is say it state is 500 and I'm going to  have message this is an error originating from the   loader in root by throwing a response and let's  also add this so let's say the user has a role of   of admin and and coincidentally he's also named  admin so his parents didn't really love him as   a child and they decided to name him as a role  privilege so now let's save this and see what   happens in the browser now as you can see in the  browser our error is yellow now because we threw a   response and the status is 500 and this means the  error boundary called the response so something   to keep in mind here is we drew a user as well so  let's actually change this to do something else   depending on the fact if the user is an admin or  not so now let's go back to vs code and the first   thing we're going to do is create a user type  so for example let's say the user is an object   that has a name so which is a string and a role  which is either our admin or an user what we're   going to do here is we're going to create another  type guard so what type guards are are special   functions that allow you to basically guard  something with a type so whenever the if check   passes inside of the if check the type is going to  be narrowed to whatever you were checking so what   we're going to do is we're going to create is user  and the value is going to be unknown and there is   a special kind of syntax here which is value is  user and this tells typescript that the value is   of type user if this is returned properly so what  we're going to do here so let's implement this   now so as I said if this function returns true it  means the user is of type user and if it returns   false it's not so because we have no idea what the  value is we have to guard it by checking the it's   of type object and what we're going to do here  is we're going to say if it's not an object or a   value do our early return we're going to check if  the name property is inside of value and that the   type of value do name is a string and we're going  to return this as well and then we're going to do   the same thing for the RO here and then we're  going to say it's true because the checks have   passed so we just check that it's a string here we  don't really check that the ru is the correct type   but you get the point so the idea is to narrow the  type so now that we narrow the type we're going to   say here if is user because we through a response  it will have data here this means that the error   data is a user so what we're going to do here is  say user is equal to error data and if I hover   over this you can see it's of type user and the  cool thing that we can do here is say if the user   rooll is an admin we're going to return something  different so we're going to return actually we'll   change this to Yellow whoops I forgot the L  and we're GNA say username is an admin they   should know better and thank you co-pilot that's  actually a cool sentence and we'll also show the   user do ro here but it's an admin but you get the  point and then we're going to say error. status   and the error status text here and let's save  this and go to the browser and see what we have   done before we go back to the browser I realized  I made a little mistake here so the user is not   returned with the error. data here it's returned  inside of the data object as a user so because   if you look at the loader here we're throwing an  object with nested properties of message and user   so what we're going to do is we're going to change  it so it's not throwing the message and the user   we're just going to throw the user object directly  so let's just change it to be a little bit more   clear so let's say this is a dummy user you fetch  from a database or whatever and then we save it   here and now if I save this and go back to the  browser what we're going to see is if I refresh   this we can see that we get admin is an admin  they should know better admin 500 so basically   this is our username here this is our user. roll  and this is our user status so this means that   we successfully guarded our error boundary and we  showed a different response depending on the user   all right now that we've done this let's go over  to pokemon. pookemon doino what we're going to   do here is the following so we're going to throw  an error and for starters let's just say whoops I   broke it and then let's add an error boundary with  remix Forge again and what we're going to do here   is say class name of background red 500 let's set  the height to 40 so it's a little bit more visible   and let's just say here something went wrong and  the error message whatever let copilot do our work   for us and as we said this is still something you  need to typ guard so what we're going to do here   is we're not going to show the message for now  because we just want to see what's going to happen   and let's save this and now what we're going to  do is because we are not throwing in root anymore   let's remove this throw Json here and let's return  n for now we don't really care and let's save this   and now let's go back to our Pokemon application  and see what's going to happen when we navigate   to this page all right so because we removed the  throne error from the root now we can see that the   root is working and if we go to Venusaur here and  then we click on any of these Pokemon we're going   to go into the arrow boundary again because  we will throw an error whenever we land in   the loader for these pages and now if I click here  you can see that we get something went wrong here   and this is the error boundary of the Pokémons  do doll sign pokemon. info and this is rendered   instead of the UI for the Pokémon so if I remove  the throne error and I save it you're going to see   the Ivysaur here if I revert it and save it it's  going to throw the error boundary as you can see   it's really granular and you can do whatever you  want and you can even return some data that was   fetched and then show that instead so for example  let's go back to the code and let's do something   different so instead of throwing this let's throw  something else let's throw a response again so   now that you're back in the code let's imagine  this scenario let's say you don't want to throw   an error you want to redirect the user somewhere  so how we're going to do that is we're going to   throw a new response and there's a special kind  of response that's a redirect response it has the   status of 302 and the headers it has a location to  where you want to throw the user so let's say when   the user lands on this page we want to throw him  back to the root so we can delete this and throw   this and let's save this and let's go back to the  browser and see what's going to happen when we   throw this all right we're back in the browser now  and let's see what's going to happen when we click   one of these Pokémon so if you remember I added  it to the Pokémon info and whenever I click one   of these Pokémon we're going to navigate to this  page so I'm going to click Bulbasaur here and as   you can see it didn't go into the arrow boundary  but we ended up here on the route so what's going   on here well there's a special kind of response  I've already told you about called a redirect   response so what redirect responses do is they  redirect the user to a different URL and instead   of going to the error boundary you basically go to  those new loaders and they handled a new request   for you so what you can do is for example if the  user is not logged in you can throw the user to   the login page and it's not going to crash it's  just going to render a different UI depending on   where you throw the user and if you go back to  the code what's important to note here is that   this is the equivalent of throwing a redirect  function from remix so you can just say this   and it's a utility that returns a response that  is equivalent to what we had before so basically   it's a utility that's going to throw this for you  and it's going to redirect the user somewhere and   that's a neat thing to know what's going on under  the hood instead of just relying on a redirect and   just wondering how that works so what's important  to take away from here is that you can redirect   users and these are special kind of responses  that are thrown that do not go into the arrow   boundary but rather they go to whatever URL you  specified and they don't crash the application so   if you want to redirect the user somewhere else  you throw a redirect if you want the user to end   up in an arrow bound you just throw a response  that's not a redirect so either a 400 500 200 it   doesn't really matter you can even throw through  hundreds it doesn't really matter as long as it's   thrown and that's going to allow you to be very  specific in where you want the user to land and   there's also another kind of error handling I  haven't talked about and those are action error   handles and what these are are basically let's  say you have a form and I'm going to use remix   Forge again it's a vs code extension for remix  if you want to download it and give it a go it's   really useful full disclosure here I created it  so I've just added everything that's useful for   me and it's great for generating boiler plate code  anyhows if I add a remix action here and let's   say you don't want your user to go into the error  boundary because you for example had form data and   then let's say you got got the Pokemon but this  Pokemon was not right so let's say if Pokemon is   I don't know equal to p Pikachu you don't really  like Pikachu you don't want him to go through what   you can do here instead of throwing you can return  ajon response so if we import this we're going to   return a Json that's going to say error Pikachu  is not allowed I hate Pikachu for example and I'm   pretty sure that's a crime in most countries but  for the sake of the argument let's say this is the   error that you send so what this is going to do is  whenever you send data to the action is going to   say if Pokemon is Pikachu I'm going to return it  otherwise I'll return null but let's say we save   this information somewhere and what you can do  here is because data is returned from the action   you can use action data and what what this allows  you to do is when you type this to be type of action when we hover over this this will either  be null undefined so these are the cases when you   haven't actually submitted anything yet or they  can be a response of this type so for example if   I say data. error it's going to be whatever  was returned from the action so because we   return Json here with the error is going to say  Pikachu is not allowed I hate Pikachu here and   then what you can do in the UI let's say imagine  you had an input so for example input uh type text   name Pokemon we can say if data. error show the  error to the user and that's how you can handle   form submission errors but keep in mind that  this is usually useful for forms and nothing   else because there's rarely a situation where  you want to return Json as errors you usually   want to throw the user somewhere or something  like that but something also to keep in mind is   if you throw here let's say a redirect this is  not going to be the type of this so you you can   see that this hasn't changed because whenever  you throw something the types script doesn't   register it as a return type so whenever you  don't want this to be polluted by some other   error handling the best thing you can do is  throw this and then what's going to happen is   this is going to redirect the user or this will  end up somewhere in the error boundary and then   whenever you use it here this is going to be  of pure type and it's going to work so that's   also something to keep in mind so instead of  returning this you should throw it but this   might have not been a great examp example because  redirects don't pollute the type anyways but Json   does so example if you throw this it's still  going to be of the same type but if you return this it's going to say it's a string because  we return string here it's going to say it's a   jsonify object of error because we return it here  or it's going to be null or undefined because we   return null in this case and it's undefined by  default so that's a neat trick you can use to   throw the users into the error boundary if  something happens that shouldn't happen so   for example let's say you checked in the database  and the Pikachu doesn't exist at all the user send   something like an ABC string then we throw the  user to the arrow boundary telling him yeah this   doesn't work at all refresh the page or bother  somebody else with your fake information and   that's all you need to know about error handling  in remix now you know how to throw errors to throw   responses when to throw them when to return  them and generally how error boundaries handle errors and that's it for today thank  you for watching another video of mine   and I hope you enjoyed it if you have any  questions feel free to comment down below   or if you like the video also feel free  to share it with others I hope it helps   you in some way and I hope you enjoy it  thank you and see you in the next one bye
Info
Channel: Alem Tuzlak
Views: 1,361
Rating: undefined out of 5
Keywords: remix.run tutorial, remix.run, remix, #RemixErrorHandling, #ReactErrorBoundary, #ErrorHandlingInRemix, #TypeScriptErrorHandling, ThrowingErrorsInRemix, #ReturningResponsesInRemix, #TypeGuardsInReact, #RemixTutorial, #WebDevErrorHandling, #RealWorldExamples, #WebDevelopmentTutorial, #ErrorBoundaryLayout, #GranularErrorHandling, #RemixForms, #VisualDiagrams, #HandlingRedirectsInRemix, #TypeSafetyInRemix, #WebDevTutorialSeries, #CodingExamples, #SubscribeForMore
Id: qoBNbHjwKIw
Channel Id: undefined
Length: 29min 32sec (1772 seconds)
Published: Fri Jan 19 2024
Related Videos
Note
Please note that this website is currently a work in progress! Lots of interesting data and statistics to come.