Reputation: 374
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:
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
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
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
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