Why does my error handler in the http library catch * all runtime errors in the application?

I am creating a prototype application using React Native 0.39, which requests some data from a remote source. To make a request, I use Axios.

The call looks pretty simple. In a component called TownsList.js I do

 class TownsList extends Component { constructor(props) { super(props); this.state = {towns: []}; } componentDidMount() { let url = "(SOME URL HERE)"; axios.get(url) .then(function(response) { // Do stuff witt the successful result }) .catch(function (error) { Alert.alert( 'Download failed', 'Unable to download data from '+url+"\nError:"+error, [{text: 'OK'}]) }); ... 

Now it’s strange that whenever I have some other runtime error in my code in the // Do stuff witt the successful result block - for example, an incorrectly circled reference to some constant or variable - this error will be handled by the Axios error handler, and also

enter image description here

This is not true. What am I doing wrong? Should I set up “general” error handling somewhere else in my application to catch these things? Or is this the intended behavior?

+7
reactjs react-native
source share
3 answers

This is natural behavior if an error occurs in a block marked as

 // Do stuff witt the successful result 

If you do not want this behavior, consider writing it as follows:

  axios.get(url) .then(function(response) { // Do stuff with the successful result }, function (error) { // any error from the get() will show up here Alert.alert( 'Download failed', 'Unable to download data from '+url+"\nError:"+error, [{text: 'OK'}]) });) }) .catch(function(error) { // any error from "doing stuff" will show up here console.error(error); }) 

The .then() method allows you to use two functions: one for success, the other for failure - the refusal of the initial promise, and not the function of success.

Since your own code fails for some reason, you certainly do not want to shut it down.

+20
source

As Malvolio mentioned, this is the expected behavior when defining a catch method on Promise, everything that throws into it will get catch'ed.

For me, the best way to handle this behavior would be to use Redux, as it would share the problems between your component (s) and the required data. Even if I really don’t know your knowledge in the React ecosystem, and you said that this is just a prototype, I think the better to use this paradigm, the sooner the better. Here is the motivation behind Redux, it is worth reading.

To get started, you need to create a redux repository that can be composed by several reducers, which will be small independent sections of your state to provide very controlled access.

Your city reducer may look like this, and also allow you to get download status and errors:

 import { handleActions } from 'redux-actions' const initialState = { data: [], isLoading: false, err: null } export default handleActions({ FETCHING_TOWNS: state => ({ ...state, isLoading: true }) FETCH_TOWNS_SUCCESS: (state, { payload }) => ({ data: payload, isLoading: false, err: null }) FETCH_TOWNS_ERROR: (state, { payload }) => ({ data: [], err: payload, isLoading: false }) }, initialState) 

And here is an example of creating a store using combineReducers :

 import { createStore, combineReducers, applyMiddleware } from 'redux' import thunk from 'redux-thunk' import towns from './towns' const reducers = combineReducers({ towns }) const store = createStore(reducers, applyMiddleware(thunk)) export default store 

To interact with your components and gears, you will need to create thunk actions (thus middleware in the store). Just keep in mind that this is just one way to deal with side effects with redux! There are several ways to handle this, but this is one of the easiest and most common to get started.

 import axios from 'axios' import { createAction } from 'redux-actions' const fetchingTowns = createAction('FETCHING_TOWNS') const fetchTownsError = createAction('FETCH_TOWNS_ERROR') const fetchTownsSuccess = createAction('FETCH_TOWNS_SUCCESS') export const fetchTowns = () => dispatch => { dispatch(fetchingTowns()) axios.get() .then(response => dispatch(fetchTownsSuccess(response))) .catch(error => { dispatch(fetchTownsError(err)) Alert.alert( 'Download failed', `Unable to download data from ${url}\nError: ${error}`, [{text: 'OK'}] ) }); } 

In order for your components to “connect” to your store, that is, they will be displayed again after changing one of their details, you will need to add a react-redux Provider at the top level of your application, and then you can decorate your components by accepting only data from which component depends.

Then your component will look like this, and if an error occurs in the rendering of the child components, it will not be intercepted by axios Promise, since it has been separated from your component.

 import React from 'react' import { View } from 'react-native' import { connect } from 'react-redux' @connect(state => ({ towns: state.towns.data }), { fetchTowns }) class TownsList extends Component { componentWillMount () { this.props.fetchTowns() } render () { const { towns } = this.props return ( <View> {towns.map(town => ( <TownComponent town={town} key={town.id}> )} </View> ) } } 

I understand that this can be a bit unpleasant if you are not familiar with all the new dependencies and configuration bits that it adds, but I can assure you that this is worth the long run!

+4
source

There may be two conditions: -

1) In my opinion, you use the try block anywhere in the code that finds its catch block in componentDidMount, so other errors get into your catch block.

2) Any warning or error in your code is free from roaming, and it was captured by your catch block, so I would recommend that you use a try block with a catch block or try finally or just finally.

like this:

 try{ axios.get(url) .then(function(response) { // Do stuff witt the successful result }) } catch(function (error) { Alert.alert( 'Download failed', 'Unable to download data from '+url+"\nError:"+error, [{text: 'OK'}]) }); 
-3
source

All Articles