抛出错误时,React-native fetch 无法设置状态
React-native fetch failing to setState when error is thrown
背景
我正在尝试使用我的 React Native 组件中的 fetch()
函数处理错误的 HTTP 响应。我使用了 here 中的代码,它建议创建一个模块来处理响应错误。
// ApiUtils.js
var ApiUtils = {
checkStatus: function(response) {
if (response.status >= 200 && response.status < 300) {
return response;
} else {
let error = new Error(response.statusText);
error.response = response;
throw error;
}
}
};
export { ApiUtils as default };
这是我的组件的代码:
import React, { Component } from 'react';
import {View, Text, StyleSheet, Slider, ListView} from 'react-native';
import GLOBAL from "../../Globals.js"
import ApiUtils from "../utils/ApiUtils.js"
class FetchedList extends Component {
constructor(props) {
super(props);
this.state = {
dataSource: new ListView.DataSource({
rowHasChanged: (row1, row2) => row1 != row2,
}),
loaded: false,
load_failed: false,
};
}
componentDidMount(){
this.fetchData();
}
fetchData(){
fetch(GLOBAL.BASE_URL + "/" + this.props.url_section + "/" + String(this.props.weekNo) + "/")
.then(ApiUtils.checkStatus)
.then((response) => {
return response.json()
})
.then((responseData) => {
if(responseData===[] || responseData.length === 0){
this.setState({
loaded: false,
load_failed: true,
});
}
else{
this.setState({
dataSource: this.state.dataSource.cloneWithRows(responseData),
loaded: true,
});
}
})
.catch(function(error){
console.log("Error:" + error.message);
this.setState({load_failed: true});
})
.done();
}
render() {
if (!this.state.loaded) {
if (this.state.load_failed){
return(
<View></View>
);
}
return this.renderLoadingView();
}
else{
return (
<ListView
dataSource={this.state.dataSource}
renderRow={this.renderComment}
/***//>
);
}
}
renderLoadingView() {
return (
<View>
<Text>Loading . . .</Text>
</View>
);
}
renderComment(comment){
return(
<Text style={styles.row}>{comment.content}</Text>
)
}
}
const styles = StyleSheet.create({
row: {
// backgroundColor: "antiquewhite",
flexDirection: "row",
justifyContent: "flex-start",
alignItems: "center",
height: 50
},
});
module.exports = FetchedList
我已确定测试服务器当前出现 502 网关错误。
我期望的行为是,当行 .then(ApiUtils.checkStatus)
抛出错误时,它应该被 .catch
函数捕获并且状态应该由 this.setState({load_failed: true});
更新。但是,我收到错误消息 ExceptionsManager.js:55 this.setState is not a function
.
我觉得这很奇怪,因为下面的代码在它上面的 .then( . . .)
函数中起作用:
this.setState({
dataSource: this.state.dataSource.cloneWithRows(responseData),
loaded: true,
});
问题
为什么 .catch
lambda 无法访问前一个函数所在的 this.setState
?我能以某种方式使用 .bind()
吗?
后续问题
如果无法在 catch
函数中访问 this.setState
,如果 HTTP 响应不佳,如何将 state.load_failed
更改为 true
?
尝试修复
我试图将异常传递给调用函数,然后从父函数更改状态,如下所示:
我将 .catch()
函数更改为:
fetchData(){
fetch(GLOBAL.BASE_URL + "/" + this.props.url_section + "/" + String(this.props.weekNo) + "/")
.then(ApiUtils.checkStatus)
.then((response) => {
return response.json()
})
.then((responseData) => {
. . .
})
.catch(function(error){
console.log("Error!");
throw error;
})
.done();
}
然后像这样更改调用函数:
componentDidMount(){
try{
this.fetchData();
}
catch(error){
this.setState({load_failed: true});
}
console.log(this.state.load_failed);
}
然而,我得到了一个简单的ExceptionsManager.js:55 Error
。
我尝试删除 .done()
,但是 catch
块无法处理异常,状态没有改变,我收到警告:Possible Unhandled Promise Rejection (id: 0):
。我意识到这可能与 javascript 中的异步函数以及错误传递给了什么有关,但我不是 100% 确定。
环境:OSX10.10,Android4.1.2,React-native 0.29.2
您的函数与您预期的 运行 在相同的上下文(this
值)中不同。要解决此问题,请使用保持相同 this
:
的箭头函数
.catch(error => {
console.log("Error:" + error.message);
this.setState({load_failed: true});
})
或显式 bind
到当前 this
:
.catch(function(error){
console.log("Error:" + error.message);
this.setState({load_failed: true});
}.bind(this))
背景
我正在尝试使用我的 React Native 组件中的 fetch()
函数处理错误的 HTTP 响应。我使用了 here 中的代码,它建议创建一个模块来处理响应错误。
// ApiUtils.js
var ApiUtils = {
checkStatus: function(response) {
if (response.status >= 200 && response.status < 300) {
return response;
} else {
let error = new Error(response.statusText);
error.response = response;
throw error;
}
}
};
export { ApiUtils as default };
这是我的组件的代码:
import React, { Component } from 'react';
import {View, Text, StyleSheet, Slider, ListView} from 'react-native';
import GLOBAL from "../../Globals.js"
import ApiUtils from "../utils/ApiUtils.js"
class FetchedList extends Component {
constructor(props) {
super(props);
this.state = {
dataSource: new ListView.DataSource({
rowHasChanged: (row1, row2) => row1 != row2,
}),
loaded: false,
load_failed: false,
};
}
componentDidMount(){
this.fetchData();
}
fetchData(){
fetch(GLOBAL.BASE_URL + "/" + this.props.url_section + "/" + String(this.props.weekNo) + "/")
.then(ApiUtils.checkStatus)
.then((response) => {
return response.json()
})
.then((responseData) => {
if(responseData===[] || responseData.length === 0){
this.setState({
loaded: false,
load_failed: true,
});
}
else{
this.setState({
dataSource: this.state.dataSource.cloneWithRows(responseData),
loaded: true,
});
}
})
.catch(function(error){
console.log("Error:" + error.message);
this.setState({load_failed: true});
})
.done();
}
render() {
if (!this.state.loaded) {
if (this.state.load_failed){
return(
<View></View>
);
}
return this.renderLoadingView();
}
else{
return (
<ListView
dataSource={this.state.dataSource}
renderRow={this.renderComment}
/***//>
);
}
}
renderLoadingView() {
return (
<View>
<Text>Loading . . .</Text>
</View>
);
}
renderComment(comment){
return(
<Text style={styles.row}>{comment.content}</Text>
)
}
}
const styles = StyleSheet.create({
row: {
// backgroundColor: "antiquewhite",
flexDirection: "row",
justifyContent: "flex-start",
alignItems: "center",
height: 50
},
});
module.exports = FetchedList
我已确定测试服务器当前出现 502 网关错误。
我期望的行为是,当行 .then(ApiUtils.checkStatus)
抛出错误时,它应该被 .catch
函数捕获并且状态应该由 this.setState({load_failed: true});
更新。但是,我收到错误消息 ExceptionsManager.js:55 this.setState is not a function
.
我觉得这很奇怪,因为下面的代码在它上面的 .then( . . .)
函数中起作用:
this.setState({
dataSource: this.state.dataSource.cloneWithRows(responseData),
loaded: true,
});
问题
为什么 .catch
lambda 无法访问前一个函数所在的 this.setState
?我能以某种方式使用 .bind()
吗?
后续问题
如果无法在 catch
函数中访问 this.setState
,如果 HTTP 响应不佳,如何将 state.load_failed
更改为 true
?
尝试修复
我试图将异常传递给调用函数,然后从父函数更改状态,如下所示:
我将 .catch()
函数更改为:
fetchData(){
fetch(GLOBAL.BASE_URL + "/" + this.props.url_section + "/" + String(this.props.weekNo) + "/")
.then(ApiUtils.checkStatus)
.then((response) => {
return response.json()
})
.then((responseData) => {
. . .
})
.catch(function(error){
console.log("Error!");
throw error;
})
.done();
}
然后像这样更改调用函数:
componentDidMount(){
try{
this.fetchData();
}
catch(error){
this.setState({load_failed: true});
}
console.log(this.state.load_failed);
}
然而,我得到了一个简单的ExceptionsManager.js:55 Error
。
我尝试删除 .done()
,但是 catch
块无法处理异常,状态没有改变,我收到警告:Possible Unhandled Promise Rejection (id: 0):
。我意识到这可能与 javascript 中的异步函数以及错误传递给了什么有关,但我不是 100% 确定。
环境:OSX10.10,Android4.1.2,React-native 0.29.2
您的函数与您预期的 运行 在相同的上下文(this
值)中不同。要解决此问题,请使用保持相同 this
:
.catch(error => {
console.log("Error:" + error.message);
this.setState({load_failed: true});
})
或显式 bind
到当前 this
:
.catch(function(error){
console.log("Error:" + error.message);
this.setState({load_failed: true});
}.bind(this))