1

I have just started with learning reactjs and trying to retrieve data through an ajax call. The component looks like this:

import React from 'react';
import ReactDOM from 'react-dom';
import $ from 'jquery';

class App extends React.Component {
   // myTitle='';

    constructor() {
        super();
        this.state = {val: 0};
        this.update = this.update.bind(this);
    }

    update() {
        var root = 'http://jsonplaceholder.typicode.com';
        $.ajax({
            url: root + '/posts/1',
            method: 'GET'
        }).then(function (data) {
            this.state.val = data.title;
        });

        console.log(this.state);
    }

    componentWillMount() {
        console.log('mounting')
    }

    render() {
        console.log('rendering!')
        return <button onClick={this.update}>{this.state.val}</button>
    }

    componentDidMount() {
        console.log('mounted')
    }

    componentWillUnmount() {
        console.log('bye!')
    }
}

When the ajaxcall comes back it returns an error where the state.val statement is:

jQuery.Deferred exception: Cannot set property 'val' of undefined TypeError: Cannot set property 'val' of undefined
    at Object.<anonymous> (http://localhost:3000/08-lifecycle-mounting/index.js:28958:33)
    at mightThrow (http://localhost:3000/08-lifecycle-mounting/index.js:32563:30)
    at process (http://localhost:3000/08-lifecycle-mounting/index.js:32631:13) 

How can I update the state and use the returning data from the ajax call?

1 Answer 1

1

Here is a demo of how you could display the data fetched with your AJAX request: http://codepen.io/PiotrBerebecki/pen/ALQxbE

First of all, in order to update your state inside the update method, follow React's official docs (https://facebook.github.io/react/docs/component-api.html#setstate):

NEVER mutate this.state directly, as calling setState() afterwards may replace the mutation you made. Treat this.state as if it were immutable.

So this line in your code:

this.state.val = data.title;

should become:

this.setState({val: data.title})

Then, the next thing to solve is to make sure that this.setState refers to your class when called inside the $.ajax()call. You can achieve this in two ways:

1. Using an arrow function:

$.ajax({
  url: root,
  method: 'GET'
}).then(data => {
  let randomNumber = Math.floor(Math.random() * data.length);
  this.setState({title: data[randomNumber].title});
});

2. Using bind(this):

$.ajax({
  url: root,
  method: 'GET'
}).then(function(data) {
  let randomNumber = Math.floor(Math.random() * data.length);
  this.setState({title: data[randomNumber].title});
}.bind(this));

Also, note that, inside your update method when you try to use console.log(this.state) straight after updating state, you will not see the updated state for reasons explained here: https://stackoverflow.com/a/39804336/4186037

Sign up to request clarification or add additional context in comments.

2 Comments

I will add a further explanation and example in a couple of minutes.
I've now added two options for updading state inside $.ajax() call and added them to the codepen.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.