提问人:Pekka 提问时间:1/1/2017 最后编辑:MayasPekka 更新时间:4/30/2017 访问量:3061
为什么我的 http 库的错误处理程序会捕获应用中的 *all* 运行时错误?
Why is my http library's error handler catching *all* runtime errors in the app?
问:
我正在使用 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'}])
});
...
现在奇怪的是,每当我在块中的代码中出现其他运行时错误时——例如,对某些常量或变量的错误引用——该错误也将由 Axios 的错误处理程序处理:// Do stuff witt the successful result
这感觉不对。我做错了什么?我是否应该在应用的其他位置设置“通用”错误处理来捕获这些内容?或者这是有意的行为?
答:
可以有两个条件:-
1)据我所知,您在代码中的任何地方都使用了try块,该块在componentDidMount中找到其捕获块,因此这就是为什么在catch块中捕获其他错误的原因。
2)您的代码中的任何警告或错误都是自由漫游的,并且已被您的catch块捕获,因此我建议您将try block与catch块一起使用,或者try with finally或just finally。
喜欢这个:
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'}])
});
如果在标记为的块中抛出错误,这是自然行为
// 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);
})
该方法允许两个函数,一个用于成功,另一个用于失败 -- 原始 promise 的失败,即成功函数的失败。.then()
由于您自己的代码本身由于某种原因而失败,因此您当然不想对此保持沉默。
评论
.then()
setState()
正如 Malvolio 所提到的,这是在 Promise 上定义方法时的预期行为,所有抛入其中的东西都会被捕获。catch
不过,对我来说,处理这种行为的最好方法是使用 Redux,因为它会将你的组件和它们需要的数据之间的关注点分开。即使我真的不了解你在 React 生态系统中的知识,而你说它只是一个原型,我觉得最好使用这种范式,越快越好。以下是 Redux 背后的动机,值得一读。
首先,你必须创建一个 redux 存储,它可以由多个 reducer 组成,这些 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 拦截,因为它已与您的组件分离。
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>
)
}
}
我知道如果您不熟悉所有新的依赖项及其添加的配置,这可能有点令人讨厌,但我可以向您保证,从长远来看,这是值得的!
评论
then
)// Do stuff witt the successful result
.catch()
.then()