guergana
guergana

Reputation: 374

How to avoid creating references of 'this' in ES6: const that = this when scope nested in React

I am reading the air-bnb javascript style guide and it says this should not be done:

23.5 Don’t save references to this. Use arrow functions or Function#bind.

// bad
function foo() {
  const self = this;
  return function () {
    console.log(self);
  };
}

// bad
function foo() {
  const that = this;
  return function () {
    console.log(that);
  };
}

// good
function foo() {
  return () => {
    console.log(this);
  };
}

I already did some research and found two answers here in stackoverflow but the accepted answer in one of them is that this cannot be circumvented:

ES6 avoid that/self

and the other one suggests using bind, but it suggested using a generator function.

Nested reference to `this` in ES6 classes

I am building a ReactJS app and I need to access setState from within a firebase Promise.

   saveSessionToDB = () => {
        const that = this;
        db.collection("sessions")
          .add({
            props: MyProps
          })
          .then(function(docRef) {
            console.log("Session written with ID: ", docRef.id);
            that.setState({ sessionID: docRef.id });
          })
          .catch(function(error) {
            console.error("Error adding document: ", error);
            that.setState({ sessionError: error });
          });
}

I tried

const {setState} = this;

and then

setState({sessionID:docRef.id});

but I get an error.

I tried binding the saveSessionToDB in the constructor to no avail, even if it's an arrow function.

Is there another way of doing this or should I just accept that sometimes I will have to still write const that = this?

Upvotes: 2

Views: 2051

Answers (3)

Andy
Andy

Reputation: 63524

You have to use arrow functions for the then and catch too:

saveSessionToDB = () => {
  db.collection("sessions")
    .add({ props: MyProps })
    .then((docRef) => {
      console.log("Session written with ID: ", docRef.id);
      this.setState({ sessionID: docRef.id });
    })
    .catch((error) => {
      console.error("Error adding document: ", error);
      this.setState({ sessionError: error });
    });
}

The reason why arrow functions are useful is that they don't have a this context of their own (or an arguments), so they adopt the this from their outer lexical environment. Which is why you can use the component's this inside the arrow function.

Upvotes: 4

Josep Vidal
Josep Vidal

Reputation: 2661

In promises that are used on screens/components and even, mostly outside of react syntax in the then() method and catch() you usually send an arrow function (There is nothing worth in the fetch context) so you keep the context from outside (In this case the React.Component context).

In your case with just two fixes (arrow function, and that to this) everything works:

saveSessionToDB = () => {
        const that = this;
        db.collection("sessions")
          .add({
            props: MyProps
          })
          .then((docRef) => { // arrow function
            console.log("Session written with ID: ", docRef.id);
            this.setState({ sessionID: docRef.id }); // that => this
          })
          .catch((error) => { // arrow function
            console.error("Error adding document: ", error);
            this.setState({ sessionError: error }); // that => this
          });
}

Upvotes: 1

Jack Bashford
Jack Bashford

Reputation: 44087

Use arrow functions for the internal functions:

.then(docRef => {
  console.log("Session written with ID: ", docRef.id);
  this.setState({ sessionID: docRef.id });
})
.catch(error => {
  console.error("Error adding document: ", error);
  this.setState({ sessionError: error });
});

Or use bind:

.then(function(docRef) {
  console.log("Session written with ID: ", docRef.id);
  that.setState({ sessionID: docRef.id });
}.bind(this))
.catch(function(error) {
  console.error("Error adding document: ", error);
  that.setState({ sessionError: error });
}.bind(this));

Upvotes: 1

Related Questions