0

I'm learning React, stumbling around trying to find the right way to do the things I want to do.

So I have a method that gets called in the constructor - let's call this getData(). This method goes out and obtains data from an external resource via a jQuery Ajax call (I may use Fetch or something else at some point, but that's not the issue), then applies some logic in the data, using the member function formatData(). The call looks something like this:

class MyClass extends React.Component {

    // .. constructor, render, etc code

    getData() { // Part of the MyClass class.

        var self = this;
        var effUrl = 'http://someurl';
        return $.ajax({
                  url: effUrl,
                  method: 'GET',
                  appendMethodToURL: false
               })
               .done(function (data) {
                   self.setState( { effString: self.formatData(data['results']) } );
               })
               .fail(function (errorHandler, soapResponse, errorMsg) {
                   alert('Error');
               })
               .always(function () {
                   alert('Always');
               });
    }

    formatData() {

        // format the returned data...
    }
}

While the code works, it is because of a hack of assigning 'this' to 'self'. Since in my code when done is called 'this' is something different (probably the returned promise object). What is the proper 'React' way to solve this problem - in essence, call a function that is a member of the component from inside of a data call?

tl;dr I would like to replace my use of 'self' in my working code with something that was a better approach.

Ev Conrad
  • 323
  • 4
  • 17
  • 2
    if you use ES6 "arrow functions", you don't have to reassign `this` - `(data) => this.setState({...})` as arrow functions have the same scope as their "parent". You can also use arrow functions for class methods: `getData = () => { ... }`, the scope will be the class scope. – Tyler Sebastian Feb 20 '17 at 21:02
  • `this` has nothing to do with React specifically. – Felix Kling Feb 20 '17 at 21:08
  • I would disagree that it's completely unrelated to React in that the appropriate lifecycle methods for fetching data and setting state are a factor in a complete answer @FelixKling. – Andy_D Feb 20 '17 at 21:13
  • I _don't_ disagree that it's a generally unoriginal question, but it's kind of a duplicate of the one you referred to _and_ the one I reference in my answer. – Andy_D Feb 20 '17 at 21:13
  • @Andy_D: that's not what the OP is asking about IMO. They say themselves that their code works, which means they must be calling `getData` in a way that works. This question seems to be only about `this`. – Felix Kling Feb 20 '17 at 21:15
  • Thanks to all, even after just a few minutes, the answers here are more useful to me than those of some of the other posted questions that I previously reviewed. Good to know that the SO police are taking their job seriously :) – Ev Conrad Feb 20 '17 at 21:23
  • @FelixKling yeah I'd agree that he's not asking about where to fetch. That bit is an innocent bystander. – Andy_D Feb 20 '17 at 21:24
  • @Tyler Sebastian if you make your comment an answer I will mark it as such, this solved my problem. – Ev Conrad Feb 20 '17 at 21:41
  • 1
    I would but @FelixKling marking it as a dupe closed it. Mateusz's answer below is more or less the same as mine, accept his. – Tyler Sebastian Feb 20 '17 at 22:51

2 Answers2

2

The answer to your question is: .bind(this). First you should bind getData() in your component's class - preferably constructor

constructor(props){
  super(props);
  this.getData = this.getData.bind(this);
}

then inside of you ajax call you should also be able to bind it like this

.done((data) => {
    this.setState( { effString: this.formatData(data['results'])     } );
 })

arrow function will bind 'this' for you

Mateusz
  • 425
  • 2
  • 5
1

You want to make your request in componentDidMount, not the constructor. I would define the request as a separate method - getData or whatever, and bind it in the constructor

constructor(props) {
  super(props);
  this.state = { effString: null };
  this.getData = this.getData.bind(this);
}

Reference on using componentDidMount for async requests: Which kinds of initialization is more appropriate in constructor vs componentWillMount?

Community
  • 1
  • 1
Andy_D
  • 4,112
  • 27
  • 19