-1
state = {
    locationData: {}
  }

  componentDidMount() {
    axios.get('...')
      .then(res => {
        const data = res.data;

        parseString(data, function (err, result) {
          this.setState({locationData: result.data[0]}, function(){console.log(this.state.locationData);})
        });
      })
  }

Gives me the error:

Uncaught (in promise) TypeError: Cannot read property 'setState' of undefined

I've found I need to bind but I don't understand how to in this instance.

dcp3450
  • 10,959
  • 23
  • 58
  • 110
  • 3
    Just append `.bind(this)` after `parseString`'s callback body or use arrow function instead – hindmost Jan 10 '19 at 18:06
  • Could you provide the `parseString` code ? – Sergio Escudero Jan 10 '19 at 18:10
  • that didn't seem to have any effect... – dcp3450 Jan 10 '19 at 18:10
  • Given your question title I just want to point out that the error message explicitly states that `this` is undefined, not `setState` or the "React state"; which should have lead you to the fact that `this` inside the `function` is no longer a reference to your component instance. And googleing the error leads right here: –  Jan 10 '19 at 18:21
  • Possible duplicate of [React - uncaught TypeError: Cannot read property 'setState' of undefined](https://stackoverflow.com/questions/32317154/react-uncaught-typeerror-cannot-read-property-setstate-of-undefined) –  Jan 10 '19 at 18:22

3 Answers3

1

As noted in the comments, you can just add .bind(this) after the function body. Generally, I think calling methods on callback functions is not very readable So my recommendation would be either to switch your callback to an arrow function, or define the callback outside and pass it in as an argument.

First approach

state = {
    locationData: {}
  }

  componentDidMount() {
    axios.get('...')
      .then(res => {
        const data = res.data;

        parseString(data, (err, result)=> {
          this.setState({locationData: result.data[0]}, function(){console.log(this.state.locationData);})
        });
      })
  }

Second approach

state = {
    locationData: {}
  }

  componentDidMount() {

    axios.get('...')
      .then(res => {
        const data = res.data;
        const callback = function (err, result) {
          this.setState({locationData: result.data[0]}, function(){console.log(this.state.locationData);})
        }
        parseString(data, callback.bind(this));
      })
  }
schu34
  • 965
  • 7
  • 25
1

The issue is due to a context loss inside the callback of the parseString function.

Use arrow functions:

componentDidMount() {
    axios.get('...')
      .then(res => {
        const data = res.data;

        parseString(data, (err, result) => {
          this.setState({locationData: result.data[0]}, () => {console.log(this.state.locationData);})
        });
      })
  }

or bind the this:

componentDidMount() {
    axios.get('...')
      .then(res => {
        const data = res.data;

        parseString(data, (function (err, result) {
          this.setState({locationData: result.data[0]}, (function(){console.log(this.state.locationData);}).bind(this))
        }).bind(this));
      })
  }
quirimmo
  • 9,800
  • 3
  • 30
  • 45
0

You can change function (err, result){...} into (err, result) => {...} since arrow function don't have own this property.

Alok Kumar
  • 81
  • 1
  • 2