1

I wanted to use axios in my react code for getting data from the server. I put axios code in the componentWillMount of my react component like this.


componentWillMount()
    {   
        axios
        .get("https://jsonplaceholder.typicode.com/Posts")
        .then(function(response) {
            this.setState({Posts : response.data[0].title});
        })
        .catch(function(error) {
            console.log(error);
        });
    }

but above code thrown me an error like this


TypeError: "this is undefined"
    componentWillMount Redux

but when I did slightly change in the code like the code below everything were going right.


componentWillMount()
    {   
        axios
        .get("https://jsonplaceholder.typicode.com/Posts")
        .then(response= > {
            this.setState({Posts : response.data[0].title});
        })
        .catch(error => {
            console.log(error);
        });
    }

Another thing that I want to say is the "this" object is active in the componentWillMount

is there anyone tell me the difference between two code above?

Ehsan Ahmadi
  • 1,382
  • 15
  • 16
  • Possible duplicate of [React this.setState is not a function](https://stackoverflow.com/questions/31045716/react-this-setstate-is-not-a-function) – nbokmans Jun 15 '19 at 18:28

5 Answers5

3

MDN says:

An arrow function [...] is an alternative to a regular function expression, although without its own bindings to the ´´this´´.

If you use a regular function, this refers to the function itself (which is undefined). When using an arrow function, this remains untouched.

Neskews
  • 764
  • 1
  • 10
  • 23
3

If you use the function(response) { ... } syntax, this is not inherited and will be undefined. You need to explicitly bind this to your React component so that it knows how to find this.setState:

componentWillMount()
{   
    axios
    .get("https://jsonplaceholder.typicode.com/Posts")
    .then(function(response) {
        this.setState({Posts : response.data[0].title});
    }.bind(this))  // <-- notice the .bind(this)
    .catch(function(error) {
        console.log(error);
    });
}

With the response => { ... } syntax the this context is inherited so this binding is not necessary.

rickdenhaan
  • 10,857
  • 28
  • 37
2

You need to use an arrow function to use this

You cannot use setState to access this when you use a function() declaration. this will return undefined, as its scope doesn't point to the object that you created. So, instead, you should use the code below,

Working code:

componentDidMount()
    {   
        axios
        .get("https://jsonplaceholder.typicode.com/Posts")
        .then(() => {
            this.setState({Posts : response.data[0].title}); // `this` object points to your object here because of the arrow function.
        })
        .catch(() => { // Same case here
            console.log(error);
        });
    }

Also, Junius is right about componentDidMount.

The best place to make calls to fetch data is within componentDidMount(). componentDidMount() is only called once, on the client, compared to componentWillMount() which is called twice, once to the server and once on the client. More Info

Fatih Aktaş
  • 1,446
  • 13
  • 25
1

bind your function or use arrow function

componentWillMount = () => {

  axios("https://jsonplaceholder.typicode.com/Posts")
    .then((response) => {
      this.setState({ Posts: response.data[0].title });
    })
    .catch(function (error) {
      console.log(error);
    });
}

Edit

please use componentDidMount instead of componentWillMount

componentDidMount = () => {}

or save the value of this in a variable.

componentDidMount = () => {

  const that = this;

  axios("https://jsonplaceholder.typicode.com/Posts")
    .then(function (response) {
      that.setState({ Posts: response.data[0].title });
    })
    .catch(function (error) {
      console.log(error);
    });
}

DEMO

<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.6.0/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.6.0/umd/react-dom.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/babel-standalone/6.21.1/babel.min.js"></script>
<script src="https://unpkg.com/axios/dist/axios.min.js"></script>
<div id="root"></div>

<script type="text/babel">

class App extends React.Component {
  constructor() {
    super();
    this.state = {
      name: 'React', 
      Posts: '',
    };
  }

    componentDidMount = () => {
      const that = this;
      axios("https://jsonplaceholder.typicode.com/Posts")
        .then(function (response) {
          that.setState({ Posts: response.data[0].title });
        })
        .catch(function (error) {
          console.log(error);
        });
    }

  render() {
    return (
      <div>
        <p>Post title</p>
        <p>{this.state.Posts}</p>
      </div>
    );
  }
}
ReactDOM.render(<App />, document.getElementById("root"));
</script>

this

This is determined at runtime and depending on the code, it can be something different.

this is

  • determined at runtime, when a function is envoked
  • determined by how a function is invoked, not where the function is defined
  • a reference to an object.
  • will always be an object
  • global (this) not available in strict mode

Example 1: this = window

var name = 'Global';

var callName1 = function() {
  var name = 'Peter';
  console.log('--- From callName1 ----');
  console.log(this.name);
  //console.log(this);
  callName2();
}


var callName2 = function() {
  var name = 'Jane';
  console.log('--- From callName2 ----');
  console.log(this.name);
  //console.log(this);
}

callName1();

var execute = function(fn) {
  var name = 'Mary';
  console.log('--- From execute ----');
  console.log(this.name);
  //console.log(this);
}

execute(callName2);

Example 2: not available in strict mode

'use strict';

var name = 'Global';

var callName1 = function() {
  var name = 'Peter';
  console.log('--- From callName1 ----');
  console.log(this.name);
  console.log(this);
}

callName1();

Example 3: examining this with method invocation

var name = 'global';

var obj = {
  name: 'James Obj1',
  func: function() {
    console.log('--- From func ----');
    console.log(this.name);
    console.log(this); // this reference obj1
  }
}

obj.func()

var obj2 = {
  name: 'Jame Obj2',
  func: obj.func // this reference obj2, but the function is defined in obj1
}

obj2.func()

var obj3 = {
  name: 'Kane Obj3',
  obj4: {
    name: 'Mary Obj4',
    func: function () {
      console.log('--- From obj4 ----');
      console.log(this.name);
      console.log(this); // this reference obj4
    }
  }
}
obj3.obj4.func()

With () => {} function this - is lexically bound. It means that it uses this from the code that contains the arrow function.

Junius L
  • 15,881
  • 6
  • 52
  • 96
1

Just a minor update, From the react docs, componentWillMount() is considered to be unsafe for async rendering. If you do choose to continue to use it, you should use UNSAFE_componentWillMount() or you can just use componentDidMount() which is only called once. The “UNSAFE” prefix refers not to security but instead conveys that code using these lifecycles will be more likely to have bugs in future versions of React, especially once async rendering is enabled.

     UNSAFE_componentWillMount()
       {   
       axios.get("https://jsonplaceholder.typicode.com/Posts")
        .then(() => {
            this.setState({Posts : response.data[0].title});
        })
        .catch(() => { 
            console.log(error);
        });
       }  

Tony Okoth
  • 157
  • 1
  • 4