为什么我的http库的错误处理程序在应用程序中捕获* all *运行时错误?

时间:2017-01-01 10:35:06

标签: reactjs react-native

我正在使用React Native 0.39构建原型应用程序,该应用程序从远程源请求一些数据。要发出请求,请使用Axios.

这个电话看起来非常简单。在名为TownsList.js的组件中,我执行

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'}])
         });

...

现在奇怪的是,每当我在// Do stuff witt the successful result块中的代码中出现其他运行时错误时 - 例如对某个常量或变量的错误引用 - 该错误将由Axios处理。错误处理程序,以及:

enter image description here

这感觉不对。我究竟做错了什么?我应该设置" generic"错误处理我的应用程序中的其他地方来捕获这些东西?或者这是预期的行为吗?

3 个答案:

答案 0 :(得分:20)

如果在标记为

的块中抛出错误,这是自然行为
// Do stuff witt the successful result

如果你不想要这种行为,可以考虑这样写:

 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);
    })

.then()方法允许两个函数,一个用于成功,另一个用于失败 - 原始promise的失败,而不是成功函数。

由于您自己的代码本身因某些原因而失败,您当然不想让它沉默。

答案 1 :(得分:4)

正如Malvolio所说,这是在Promise上定义catch方法时的预期行为,抛出的所有内容都会被捕获。

对我而言,处理这种行为的最佳方法是使用Redux,因为它会将您的组件与所需数据之间的关注分开。即使我真的不知道你在React生态系统中的知识,并且你说它只是一个原型,我觉得最好使用这个范例,越快越好。以下是Redux背后的the motivations,值得一读。

要开始使用,您必须create a redux store,它可以由代表您所在州的小型独立分区的多个Reducer组成,以实现非常受控的访问。

您的城镇减速机可能看起来像这样,并且还允许您获得加载和错误状态:

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)

以下是使用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

要连接组件和reducer,您必须创建thunk操作(因此商店中的中间件)。 请注意,这只是使用redux处理副作用的一种方法!有多种方法可以解决这个问题,但这是以开头最简单和最常见的方式之一。

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'}]
       )
     });
}

要使您的组件“连接”到您的商店,这意味着一旦其中一个道具发生变化,它们将再次渲染,您必须在您的顶层添加react-redux Provider组件应用程序,然后您可以装饰您的组件,只获取组件所依赖的数据。

您的组件将如下所示,如果在子组件的呈现中发生错误,它将不会被Axios Promise截获,因为它已与您的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>
    )
  }

}

我知道如果你不熟悉所有新的依赖项和它添加的配置,这可能有点令人讨厌,但我可以向你保证,从长远来看它是值得的!

答案 2 :(得分:-3)

可能有两个条件: -

1)据我所知,你在代码中的任何地方都使用try block,它在componentDidMount中找到了catch块,这就是为什么在catch块中捕获了其他错误的原因。

2)你的代码中的任何警告或错误都是漫游的,并且它被catch块捕获,所以我建议你使用带有catch块的try块或者最后尝试或者最后尝试。

像这样:

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'}])
         });