Search code examples
javascriptreactjsaxiosfetchuse-effect

React app 'crashes' due to fetch/axios inability to correctly pass error to catch block


I have a small React app that fetches some resources with axios through UseEffect() hook. The app itself works fine in debug. However, when I try to test out the build version of my app, it 'crashes', that is, it doesn't render anything aside from setting body background color.

When in debug mode, the app shows 0 errors or warnings, and the only leads the build has is TypeError's for built-in type-specific methods like .map(), .filter() and .toLowerCase() all which, conveniently, are present in components that fetch data with axios. After some testing I came to conclusion that the cause of the 'crash' was axios (and fetch()) that, for a reason unknown to me, doesn't pass the error upon unsuccessful fetch to the .catch() block and tries instead to execute .then() with undefined data, which, in turn, don't have methods like .map() or .toLowerCase(), cause TypeError's and 'crash' the whole app.

I tried to rewrite all axios containing components with fetch(), but the result is the same. The closest thing I have found on my own was this answer for React Native (and not plain React) that advises to change console.error() (which crashes the app) to console.log(), but it's hardly applicable in my case since I don't use console.error() at all.

Below you can find a sample component that fetches data with axios:

import axios from 'axios';
import { useState, useEffect } from 'react';

const Salute = () => {
  const [user, setUser] = useState('john doe');

  useEffect(() => {
    axios
      .get('/api/user?id=1')
      .then(({ data: { fullName } }) => setUser(fullName.toLowerCase()))
      .catch((err) => console.log(err));
  }, []);

  return (
    <div className='salute'>
      <h1>
        hi, it's <span id='username'>{user}</span>
      </h1>
    </div>
  );
};

export default Salute;


Solution

  • The root cause of my problem turned out to be faulty API which sends error message with a 200 status code, which in turn was interpreted by axios/fetch() as a normal response.

    The key takeaway here (at least for me) is to implement at least some minimal data validation in fetching logic so as to prevent the cases like these. In my case, I did the following (until the API I use gets fixed):

    import axios from 'axios';
    import { useState, useEffect } from 'react';
    
    const Salute = () => {
      const [user, setUser] = useState('john doe');
    
      useEffect(() => {
        axios
          .get('/api/user?id=1')
          .then(({ data }) => {
    
            if (typeof data.fullName === 'string') {
              setUser(data.fullName.toLowerCase());
            } else {
              console.log('[AXIOS GET] Wrong data type: ' + typeof data.fullName);
            }
          })
          .catch((err) => console.log('[AXIOS GET]', err));
      }, []);
    
      return (
        <div className='salute'>
          <h1>
            hi, it's <span id='username'>{user}</span>
          </h1>
        </div>
      );
    };
    
    export default Salute;