Today I Learned

TIL, 2023-04-20

How to handle errors in React: full guide

Reference

  • Starting from version 16, an error thrown during React lifecycle causes the entire app to unmount itself if not stopped.
  • Before, components would be preserved on the screen. Now, an uncaught error will destroy the entire page.
  • try catch - can do also in promises.
    • This doesn’t work with useEffect because it’s called asynchronously after render.
try {
  useEffect(() => {
    throw new Error('Hulk smash!');
  }, [])
} catch(e) {
  // useEffect throws, but this will never be called
}
  • This is the way to fix this:
useEffect(() => {
 try {
   throw new Error('Hulk smash!');
 } catch(e) {
   // this one will be caught
 }
}, [])
  • try catch doesn’t work well in children components.
  • This doesn’t work:
const Component = () => {
  try {
    return <Child />
  } catch(e) {
    // still useless for catching errors inside Child component, won't be triggered
  }
}
  • This is happening because when we write <Child />, we are not actually rendering this component. We are creating a component Element, which is just a component’s definition.
  • Other limitation: setting state during render is a no-no.

  • Infinite re-renders:
const Component = () => {
  const [hasError, setHasError] = useState(false);

  try {
    doSomethingComplicated();
  } catch(e) {
    // don't do that! will cause infinite loop in case of an error
    // see codesandbox below with live example
    setHasError(true);
  }
}

React ErrorBoundary component

  • A special API that turns a regular component into a try/catch statement in a way, only for React declarative code.

This project is maintained by daryllxd