简体   繁体   English

引发错误时,React-Native提取无法设置为setState

[英]React-native fetch failing to setState when error is thrown

Background 背景

I am trying to handle a bad HTTP response with the fetch() function in my React Native Component. 我正在尝试使用我的React Native组件中的fetch()函数处理错误的HTTP响应。 I have used the code from here which suggests creating a module to handle response errors. 我从这里使用了建议创建一个模块来处理响应错误的代码。

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

This is the code for my component: 这是我的组件的代码:

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

I have made sure that the test server is currently giving 502 Gateway errors. 我已确保测试服务器当前出现502网关错误。

The behaviour I expect is that when an error is thrown by the line .then(ApiUtils.checkStatus) it should be caught by the .catch function and state should be updated by this.setState({load_failed: true}); 我期望的行为是,当.then(ApiUtils.checkStatus)行引发错误时,应通过.catch函数捕获该.catch并应通过this.setState({load_failed: true});更新状态this.setState({load_failed: true}); . However, I get the error message ExceptionsManager.js:55 this.setState is not a function . 但是,我收到错误消息ExceptionsManager.js:55 this.setState is not a function

I find this odd because the following works within the .then( . . .) function above it: 我觉得这很奇怪,因为以下内容在其上方的.then( . . .)函数中起作用:

this.setState({
  dataSource: this.state.dataSource.cloneWithRows(responseData),
    loaded: true,
});

Question

Why does the .catch lambda not have access to this.setState where the previous function does? 为什么.catch lambda无法访问上一个函数所在的this.setState Can I use .bind() somehow? 我可以以某种方式使用.bind()吗?

Follow-On Question 后续问题

If it is not possible to access this.setState within the catch function, how can I change state.load_failed to true if I get a poor HTTP response? 如果无法在catch函数中访问this.setState ,如果收到较差的HTTP响应,如何将state.load_failed更改为true

Attempted Fixes 尝试的修复

I attempted to pass the exception to the calling function and then change the state from the parent function, like so: 我试图将异常传递给调用函数,然后从父函数更改状态,如下所示:

I changed the .catch() function to this: 我将.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();
  }

and then changed the calling function like so: 然后像这样更改调用函数:

componentDidMount(){
try{
  this.fetchData();
}
catch(error){
  this.setState({load_failed: true});
}
console.log(this.state.load_failed);

} }

However, I then get a simple ExceptionsManager.js:55 Error . 但是,然后我得到一个简单的ExceptionsManager.js:55 Error

I tried removing .done() , but the catch block fails to handle the exception, state does not change and I get a warning: Possible Unhandled Promise Rejection (id: 0): . 我尝试删除.done() ,但是catch块无法处理该异常,状态没有更改,并且收到警告: Possible Unhandled Promise Rejection (id: 0): I realise that this may have something to do with async functions in javascript and what the error is passed to, but I'm not 100% sure. 我意识到这可能与javascript中的异步函数以及错误会传递给什么有关,但我不确定100%。

Environment: OSX 10.10, Android 4.1.2, React-native 0.29.2 环境:OSX 10.10,Android 4.1.2,React-native 0.29.2

Your function is not running in the same context ( this value) as you expect. 您的函数未在您期望的相同上下文( this值)中运行。 To solve this, either use an arrow function which keeps the same this : 为了解决这个问题,请使用箭头功能,保持相同this

.catch(error => {
  console.log("Error:" + error.message);
  this.setState({load_failed: true});
})

or explicitly bind to the current this : 或显式bind到当前this

.catch(function(error){
  console.log("Error:" + error.message);
  this.setState({load_failed: true});
}.bind(this))

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM