lkemitchll
lkemitchll

Reputation: 2751

Working with arrays of objects as props in React

I'm building a small app that consumes a REST api. I'm running into problems displaying information inside arrays of objects, see code below:

actions.js

import axios from 'axios'

function fetchService () {
  return axios.get('http://localhost:5000/ldbws-rest-proxy/v0.1/departure-board/IPS')
    .then(function (response) {
      return {
        service: response.data.trainServices[0]
      }
    })
    .catch(function (response) {
      console.log(response)
    })
}

export default fetchService

train_service.js

import fetchService from '../actions'

import DepartureTime from './departure_time'
import OriginStation from './origin_station'

var TrainService = React.createClass ({
  getInitialState () {
    return {
      service: []
    }
  },
  componentDidMount () {
    fetchService()
      .then(function (dataObj) {
        this.setState({
          service: dataObj.service
        })
      }.bind(this))
  },
  render () {
    return (
      <section>
        <DepartureTime time={this.state.service.std} />
        <OriginStation name={this.state.service.origin[0].crs} />
      </section>
    )
  }
})

export default TrainService

JSON sample (response.data.trainServices[0])

{
  "destination": [
    {
      "crs": "CBG",
      "locationName": "Cambridge"
    }
  ],
  "etd": "On time",
  "operator": "Greater Anglia",
  "operatorCode": "LE",
  "origin": [
    {
      "crs": "IPS",
      "locationName": "Ipswich"
    }
  ],
  "serviceID": "ILZn7gyLj+eoZZfyaFlP0w==",
  "std": "12:20"
}

The problem is that <OriginStation name={this.state.service.origin[0].crs} /> throws an error:

TypeError: undefined is not an object (evaluating 'this.state.service.origin')

I'm not sure why this isn't working, if I do console.log(dataObj.service.origin[0].crs) inside componentDidMount it outputs fine. I think it's something to do with the origin array...

Any help appreciated.

EDIT:

Screenshot of the state in the Chrome Inspector:

Screenshot

Upvotes: 2

Views: 677

Answers (2)

Andrew Paramoshkin
Andrew Paramoshkin

Reputation: 989

It's because your TrainService render method calls earlier than fetchService promise resolves. Easiest way to fix your error is wait for fetchService updates service state:

var TrainService = React.createClass ({
  getInitialState () {
    return {
      service: null
    }
  },
  componentDidMount () {
    fetchService()
      .then(function (dataObj) {
        this.setState({
          service: dataObj.service
        })
      }.bind(this))
  },
  render () {
    if (this.state.service === null)
      return null;
    return (
      <section>
        <DepartureTime time={this.state.service.std} />
        <OriginStation name={this.state.service.origin[0].crs} />
      </section>
    )
  }
})

Upvotes: 2

ganesshkumar
ganesshkumar

Reputation: 1377

fetchService is making an async call. So when componentDidMount is run, it will make an async call and proceeds to render.

When the render function is executed for the first time you state is not populated with the data and it has an empty array for this.state.service, from getInitialState.

If you are writing console.log inside componentDidMount as

componentDidMount () {
    fetchService()
        .then(function (dataObj) {
             console.log(dataObj.service.origin[0].crs)
             this.setState({
                  service: dataObj.service
             })
        }.bind(this))
},

the console.log gets executed only when the async call has succeeded, so the data is available.

To solve this either don't render the component until the state data is ready.

render() {
    this.state.service.length == 0 && return null
    ...
}

Upvotes: 0

Related Questions