0

So I am trying to have a text element that displays a certain child from JSON (gotten using fetch). I have trying setting the response from fetch equal to this.state.json (declared in the constructor). Then I use a Text element with this.state.json.current.name (which is a valid child in the Airtime API), but I get an error saying undefined is not an object while evaluating this.state.json.current.name. I have tried making the function synchronous and asynchronous (I thought maybe the JSON wasn't loaded while text tried to be displayed), but nothing worked.

  fetchJSON = async () => {
    fetch('http://IPADDRESS/api/live-info', {
      method: 'get',
      dataType: 'jsonp',
      headers: {
         'Accept': 'application/json',
         'Content-Type': 'application/json'
      }
  }).then((response) => {
       return response.json()
  }).then((responseData) => {
        this.setState({json: responseData})
        this.setState({isLoadedJSON: true})
        return responseData;
    })
  .catch(function(err) {
      console.log(err);
  })
  }

then I just call await this.fetchJSON() in componentWillMount(). For displaying text I just have <Text>{this.state.json.current.name}</Text>, but this doesn't work and I'm not sure if its a React issue or my issue. this.state.json.env works fine, but any further nested items, such as this.state.json.current.name, It displays undefined is not an object. I have also tried having an isLoadedJSON state and either an if or while before rendering, so it render a blank View while JSON is loading, but that then displays a blank View for ever. Any thanks would be very highly appreciated.

{
  "env": "production",
  "schedulerTime": "2018-02-15 13:37:50",
  "previous": {
    "name": "REDACTED",
    "starts": "2018-02-15 08:15:00",
    "ends": "2018-02-15 08:29:51.611",
    "type": "track"
  },
  "current": {
    "name": " - TVP",
    "starts": "2018-02-15 09:20:00",
    "ends": "2018-02-15 10:00:00",
    "media_item_played": true,
    "record": 0,
    "type": "track"
  },
  "next": {
    "name": "REDACTED",
    "starts": "2018-02-15 11:10:00",
    "ends": "2018-02-15 11:15:06.077",
    "type": "track"
  },
  "currentShow": [
    {
      "0": "2018-02-15 09:20:00",
      "1": "2018-02-15 10:00:00",
      "2": "REDACTED",
      "3": 33,
      "4": 273,
      "5": 0,
      "6": "",
      "7": "2018-02-15 09:20:00",
      "8": "2018-02-15 10:00:00",
      "start_timestamp": "2018-02-15 13:20:00",
      "end_timestamp": "2018-02-15 14:00:00",
      "name": "REDACTED",
      "id": 33,
      "instance_id": 273,
      "record": 0,
      "url": "",
      "starts": "2018-02-15 13:20:00",
      "ends": "2018-02-15 14:00:00"
    }
  ],
  "nextShow": [
    {
      "id": 23,
      "instance_id": 138,
      "name": "REDACTED",
      "url": "",
      "start_timestamp": "2018-02-15 15:10:00",
      "end_timestamp": "2018-02-15 15:20:00",
      "starts": "2018-02-15 15:10:00",
      "ends": "2018-02-15 15:20:00",
      "record": 0,
      "type": "show"
    }
  ],
  "timezone": "GST",
  "timezoneOffset": "14400",
  "AIRTIME_API_VERSION": "1.1"
}

Pastebin

2
  • Can you post the responseData ? And I would recommend you to call fetchJSON inside componentDidMount instead of componentWillMount. More about that you can read on this nice article daveceddia.com/… Commented Feb 15, 2018 at 9:37
  • Edited for @Ionut Commented Feb 15, 2018 at 9:42

2 Answers 2

2

The problem is probobly related to that when the render happens the response not being received and the json object on stat not yet set.

What you can do is to set a second state variable called like name and use that to display text.

Example

  fetchJSON = async () => {
    fetch('http://IPADDRESS/api/live-info', {
      method: 'get',
      dataType: 'jsonp',
      headers: {
         'Accept': 'application/json',
         'Content-Type': 'application/json'
      }
  }).then((response) => {
       return response.json()
  }).then((responseData) => {
        this.setState({
          json: responseData,
          name: responseData.current.name,
          isLoadedJSON: true
        });
        return responseData;
    })
  .catch(function(err) {
      console.log(err);
  })
  }

  //...
  <Text>{this.state.name}</Text>
Sign up to request clarification or add additional context in comments.

7 Comments

What about the weirdness when it comes this.state.json.env always working while no further nested objects work
@PhilipposSlicher I'm not really sure what causing that.
Yes, and no changes to the server providing the JSON either
@PhilipposSlicher can you please add more complete and recent version of an example of your code to the question please
Added PasteBin link
|
0

What is actually happening here? The rendering triggers multiple times before the async request response. You can also check if the state has been set with the json by using this.state.json&& conditional rendering to check if json exists in state:

class Testing extends React.Component {
  constructor(props) {
    super(props)
    this.state = {
    }
  }
  componentWillMount(){
    this.fetchJSON()     
  }
  fetchJSON() {
    fetch('https://api.myjson.com/bins/q6edh', {
        method: 'get',
        dataType: 'jsonp',
        headers: {
          'Accept': 'application/json',
          'Content-Type': 'application/json'
        }
      }).then((response) => {
        return response.json()
      }).then((responseData) => {
        this.setState({
          json: responseData
        })
        this.setState({
          isLoadedJSON: true
        })
        //console.log(this.state);
        return responseData;
      })
      .catch(function(err) {
        console.log(err);
      })
  }
  render() {
    return ( 
    <div>{this.state.json&& <p>And the name is: {this.state.json.current.name}</p>}</div>
    )
  }
}
ReactDOM.render( <Testing/> ,
  document.getElementById('root')
);
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react-dom.min.js"></script>
<div id='root'></div>

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.