Why shouldn’t I use catch() to handle errors in React useEffect API calls?

Everything I can find on this seems to link back to this github issue circa 2016. I’ll quote verbatim from there since it doesn’t appear to have been covered on Stack Overflow before and it explains things pretty thoroughly:


.then(() => {
  this.setState({ loaded: true })
})
.catch(()=> { 
  console.log('Swallowed!') 
});

Your catch() handler is going to catch any error thrown in the then()
chain before it, including the one caused by a render() due to a
setState() call.

Even if you don’t use setState directly, you may have the same problem
if some other code you call uses it (for example, a Redux dispatch()).

If you don’t want to catch errors resulting from setState(), and want
to only catch network failures (let’s imagine your Promise.resolve()
is actually a fetch()), you want to use the second then() argument
instead:

componentDidMount() {
  Promise.resolve()
  .then(() => {
      this.setState({ loaded: true })
  }, (err) => {
    console.log('An error occurred (but not in setState!)', err);
  });
}

In this case, unless you catch() later in the chain, the error in
render() will be uncaught and, with a good Promise polyfill (or with
native Promises in Chrome and maybe other browsers), displayed.


Edit: following the answer from @Martin I went and tested this, and I can confirm that this no longer appears to be a relevant concern. Render errors from setState are not caught in any version of React from v16.0 onwards, and since useState was only introuduced in v16.8, it doesn’t seem possible that this could ever have been an issue for hooks.

Here is a codesandbox which demonstrates the original issue in the older versions of React.

Leave a Comment

Hata!: SQLSTATE[HY000] [1045] Access denied for user 'divattrend_liink'@'localhost' (using password: YES)