Search code examples
reactjsclosuresjavascript-objects

How to access state from closure in React


My assumption is that I try to access state from a closure. This does somehow not work:

Present Code:

export class CityChoice extends React.Component{
constructor(props) {
    super(props);
    this.state={}
}

componentDidMount(){
  request
    .get('http://XXX.XXX.XX.XX:3000/get_courses')
    .set('Accept', 'application/json')
    .then((res) => {
        for (let key in res.body){
          console.log(res.body[key].city)
        }
      this.setState({courses: res.body})
        console.log("this.state.courses -> " + this.state.courses)
    })
    .catch(function(err) {
      console.log(err)
    });
}

render(){
  var that = this
  return (<div>
            <h2>Wähle Deine Stadt</h2>
            {
            that.state.courses.body.city.map((city, index) => (
              <p><Link to={{pathname: "/kurse", stadt: {city}}}><Button>{city}</Button></Link></p>
            ))}
            }
          </div>
        )
    }
}

Expected Result

Output of x Buttons named and linked to the respective cities.

Actual Result

TypeError: that.state.courses is undefined


Solution

  • Your component tries to render courses before your async fetch finishes. So, use a conditional rendering if you can't initialize your courses to an appropriate null state as @Tarik Sahni suggested.

    {
        !this.state.courses
        ? ""
        : this.state.courses.body.city.map((city, index) => (
            <p><Link to={{pathname: "/kurse", stadt: {city}}}><Button>{city}</Button></Link></p>
        ))}
    }
    

    or maybe more concise

    {
        this.state.courses && this.state.courses.body.city.map((city, index) => (
            <p><Link to={{pathname: "/kurse", stadt: {city}}}><Button>{city}</Button></Link></p>
        ))}
    }
    

    You don't need to assign this to that in your render function