micl
micl

Reputation: 91

React.js: can't get an property in an array of objects in render() function

how to I get the property of an array of objects in the render function. if I try this:

render() {
    console.log(this.state.items[0].name);
 (...)

I got an error:

TypeError: this.state.items[0] is undefined

  class App extends React.Component {
  constructor() {
    super()

    this.state = {
      items: []
    }
  }
  componentWillMount() {
    fetch('http://swapi.co/api/people/?format=json')
      .then((response) => response.json())
        .then(({ results: items }) => this.setState({ items }))
  }

  filter(e){
    this.setState({ filter: e.target.value })
    console.log(this.state.items[0].name);
  }

  render() {
    console.log(this.state.items[0].name);
    return (
      <div>
        <input type="text" onChange={this.filter.bind(this)}  />
      </div>
    )
  }

}
export default App

However, if I log out only the first element of the array

 console.log(this.state.items[0])

it prints out the object

Object { name: "Luke Skywalker", height: "172", mass: "77", hair_color: "blond", skin_color: "fair", eye_color: "blue", birth_year: "19BBY", gender: "male", homeworld: "http://swapi.co/api/planets/1/", films: Array[5], 6 more… }

When the filter function get fired I do get the property of the first element console.log(this.state.items[0].name)

prints out:

Luke Skywalker

What's happening here?

Upvotes: 2

Views: 3041

Answers (2)

Mayank Shukla
Mayank Shukla

Reputation: 104529

fetch is asynchronous call, so during first time rendering this.state.items will [] and you are trying to access the name of 0th item that doesn't exist, and it is throwing the error because of that.

When you are using:

console.log(this.state.items);

Check the console it was printing two values one [] and another one will be the data that you are getting from server.

Solution:

Put the check on length inside render it will print the proper name once you get the response.

Like this:

render(){
   if(this.state.items.length)
       console.log(this.state.items[0].name);

   return(
       ....
   )
}

Upvotes: 1

TheTFo
TheTFo

Reputation: 811

Your state.items array is not set until your fetch has completed. Your render method will be called prior to this, therefore, it won't work as expected.

If you recheck your console output, I have a feeling you'll see some nulls or undefined's prior to the your object showing.

Try this:

 render() {
    console.log(this.state.items.length > 0 ? this.state.items[0].name : 'Items not loaded yet');
    return (
      <div>
        <input type="text" onChange={this.filter.bind(this)}  />
      </div>
    )
  }

Upvotes: 2

Related Questions