Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why 'this' is undefined inside a Promise call

I don't understand what's going on

componentDidMount() {
    console.log('componentDidMount');
    //const self = this; 
    let _id = this.props.match.params.id.toUpperCase();

    if (_id != this.state.id.toUpperCase()) {

        axios.get('/data/pricemultifull?fsyms=' + _id + '&tsyms=USD')
            .then(response => {
                // let _currentcoin = { ...resp.data.RAW.BTC.USD, ticker: _id };
                this.setState({ id: _id }); //this == undefined
            });
    }
}

I can get a response back but this is always undefined and I'm unable to setState. I'm using an arrow function which I thought was scope 'this' to the component level. I can fix it by making a new var and setting 'this' before I make the request. I know that this should be working though. What am I missing?

My entire component

import React, { Component } from 'react';
import axios from '../../axios';


class CoinViewer extends Component {

state = {
    coin: {},
    hasLoaded: false,
    id: ''
}

componentDidMount() {
    console.log('componentDidMount');
    //const self = this; 
    let _id = this.props.match.params.id.toUpperCase();

    if (_id != this.state.id.toUpperCase()) {

        axios.get('/data/pricemultifull?fsyms=' + _id + '&tsyms=USD')
            .then( resp => {
                // let _currentcoin = { ...resp.data.RAW.BTC.USD, ticker: _id };
                this.setState({ id: _id });
            });
    }
}

componentWillMount() {

}

componentWillUpdate() {


}

componentDidUpdate() {

}

getCompleteCoinData(_id) {

}


render() {


    return (
        <div>
            CoinViewer Component: {this.state.id} sads
        </div>
    )
}

}

export default CoinViewer

like image 692
Kai CriticallyAcclaimed Cooper Avatar asked Jun 07 '18 17:06

Kai CriticallyAcclaimed Cooper


People also ask

Can a Promise return undefined?

If a handler function: returns a value, the promise returned by then gets resolved with the returned value as its value. doesn't return anything, the promise returned by then gets resolved with an undefined value.

Why this is undefined in Nodejs?

A variable that has not been assigned a value is of type undefined . A method or statement also returns undefined if the variable that is being evaluated does not have an assigned value. A function returns undefined if a value was not returned .

How do you call a Promise inside a Promise?

Here we need to first declare a Promise by using the Promise syntax, and we will be using the then() method for its execution and then inside that then() method we will create another promise by using the same Promise syntax as illustrated above, and then we will call our result of first inside that new Promise.

What is the problem with promises in JavaScript?

Promises have an API which encourages casually dangerous code. Promises lack a convenient API to safely work with data. Promises co-mingle rejected promises and unintended runtime exceptions.


3 Answers

:Edit Wow, the below is kinda true, but the real issue is you didn't initialize state. https://reactjs.org/docs/react-component.html#constructor

constructor() {
  super();
  this.state = {
    coin: {},
    hasLoaded: false,
    id: ''
  }
}

You could use lexical scoping and fix like this, this is a popular pattern to protect this.

Basically, when you use promises or functions from other libraries/ APIs you do not know what they have set their context inside the callback functions to.

In order to use the context you want, you keep the context you need saved in a variable within scope and reference it there _this, rather than by pointing to the context this. I'd recommend reading 'you dont know js' to understand this concept further.

componentDidMount() {
  console.log('componentDidMount');
  const _this = this; 
  let _id = _this.props.match.params.id.toUpperCase();

  if ( _id != _this.state.id.toUpperCase() ) {
    axios.get('/data/pricemultifull?fsyms=' + _id + '&tsyms=USD')
      .then(response => {
        _this.setState({ id: _id }); //this == undefined
      });
  }
}
like image 116
Eric Hasselbring Avatar answered Sep 21 '22 19:09

Eric Hasselbring


Solution 1: arrow functions..

requestSuccess = (resp) => {
  // let _currentcoin = { ...resp.data.RAW.BTC.USD, ticker: _id };
  this.setState({ id: _id });
}

componentDidMount() {
  console.log('componentDidMount');
  //const self = this; 
  let _id = this.props.match.params.id.toUpperCase();
  if (_id != this.state.id.toUpperCase()) {
     axios.get('/data/pricemultifull?fsyms=' + _id + '&tsyms=USD')
       .then(this.requestSuccess);
  }
}

Solution 2: binding

componentDidMount() {
  console.log('componentDidMount');
  //const self = this; 
  let _id = this.props.match.params.id.toUpperCase();
  if (_id != this.state.id.toUpperCase()) {
     axios.get('/data/pricemultifull?fsyms=' + _id + '&tsyms=USD')
       .then((resp) => {
          // let _currentcoin = { ...resp.data.RAW.BTC.USD, ticker: _id };
          this.setState({ id: _id });
     }.bind(this));
  }
}
like image 22
Medet Tleukabiluly Avatar answered Sep 22 '22 19:09

Medet Tleukabiluly


When working with React.js, chances are you have faced a problem how to access this from inside the promise.There is more than one solution to resolve this reference inside the promise. The old approach would be setting the self = this reference While this would work, the recommended solution, which is more inline with ES6, would be to use an arrow function here:

class Component extends React.Component { 
  componentDidMount() {
    let component = this;
    axios.get('http://…').then(function(data) {
      component.setState( { name: data.blah } );
    });
  }
}

The arrow syntax, as stated above, is a much smarter way to allow use of this to make reference to React.Component classes, as we can see below:

class Component extends React.Component { 
  componentDidMount() {
    axios.get('http://…').then(data => {
      this.setState( { name: data.blah } );
    });
  }
}

Please note, instead of using function(data) { //body }, we used data => { //body }, and in this case this reference won’t get the promise instance back.

like image 34
Saurabh Avatar answered Sep 24 '22 19:09

Saurabh