1

I am trying to get data from a sample api, I keep getting the error:

Cannot read property 'setState' of undefined.

Can anyone please tell me why I get the undefined error, do I need to bind to this?

import React, { Component } from 'react';
import axios from 'axios';
import logo from './logo.svg';
import './App.css';
import '../node_modules/bootstrap/dist/css/bootstrap.css';
import '../node_modules/bootstrap/dist/css/bootstrap-theme.css';

import Users from './components/Users.js';

class App extends Component {

constructor(props) {
    super(props);
    this.state = {users: []};
}


getUsers(){ 
     axios.get('http://jsonplaceholder.typicode.com/users')
.then(function (response) {
     this.setState({ users: response.data });
})
.catch(function (error) {
  console.log(error);
  });
}

componentDidMount(){
     this.getUsers();
}

render() {
return (
  <div className="App">
    <div className="App-header">
      <img src={logo} className="App-logo" alt="logo" />
      <h2>Welcome to React</h2>
    </div>

      <Users data={this.state.users} />

  </div>
);
   }
  }

export default App;
Chris
  • 57,622
  • 19
  • 111
  • 137
Bomber
  • 10,195
  • 24
  • 90
  • 167

1 Answers1

1

This happens because this is a different object inside the scope of the callback. That's why it complains that setState() doesn't exist - it's the wrong object.

The easiest solution is a so-called arrow function. The reason this solves your issue is because arrow functions, unlike the traditional functions, do not bind the this object. As such, the this object inside the callback is the "correct" one and you can call setState().

This is what the MDN documentation says on arrow functions:

An arrow function expression has a shorter syntax than a function expression and does not bind its own this, arguments, super, or new.target. These function expressions are best suited for non-method functions, and they cannot be used as constructors.

and

An arrow function does not create its own this context, so this has its original meaning from the enclosing context.

So your function would become:

getUsers(){ 
  axios.get('http://jsonplaceholder.typicode.com/users')
  .then((response) => {
     this.setState({ users: response.data });
  })
  .catch((error) => {
    console.log(error);
  });
}

The catch doesn't need changing since you are only logging to the console and don't use the this object - but I changed it anyway for consistency.

Chris
  • 57,622
  • 19
  • 111
  • 137