class App extends Component {
constructor(props) {
...
}
onChange = (e) => this.setState({term: e.target.value})
onSubmit(e){
e.preventDefault();
const api_key = "C1hha1quJAQZf2JUlK";
const url = `http://api.giphy.com/v1/gifs/search?q=${this.state.term}&api_key=${api_key}`;
}
render() {
return (
<div>
<form onSubmit={this.onSubmit}>
<input value={this.state.term} onChange={this.onChange}/>
<button>Search!</button>
</form>
</div>
);
}
}
What is the difference between the two type of functions declared in the class (onChange and onSubmit). I get an error on referencing this.sate in const url if I declare it as an ES6 class method but changing it to arrow function fixes it.
I want to know how exactly 'this' is handled in both the cases
Also, how do I do it the other way? Say, if I want to use the same onSubmit function (ES6 class method) but want to handle this when I call it (in the form element), how do I do it ?
Using this.onSubmit.bind(this) ?
Arrow functions in ES6 have at least two limitations: Don't work with new and cannot be used when creating prototype. Fixed this bound to scope at initialisation.
It's a new feature that introduced in ES6 and is called arrow function. The left part denotes the input of a function and the right part the output of that function.
There is a noticeable difference between the syntax of es5 functions and es6 arrow functions. //es6 arrow functions const printHelloWorld = () => console. log('Hello World'); In the above syntax we can put the curly braces {} after the token=>.
Arrow functions were introduced in ES6. Arrow functions allow us to write shorter function syntax: let myFunction = (a, b) => a * b; Try it Yourself »
An arrow function expression has a shorter syntax than a function expression and does not have its own this, arguments, super, or new.target. These function expressions are best suited for non-method functions, and they cannot be used as constructors.
Arrow Functions lexically bind their context so this actually refers to the originating context.
In ES3/4 functions declaration you can use this
by storing in some other variable.
const that = this;
onSubmit(e){
e.preventDefault();
const api_key = "***************";
const url = `http://api.giphy.com/v1/gifs/search?q=${that.state.term}&api_key=${api_key}`;
}
It's important to know that this syntax:
class A {
method = () => {}
}
is just syntactic sugar for creating an instance method in the class constructor:
class A {
constructor() {
this.method = () => {}
}
}
Note: This syntax is not an official part of the JavaScript language yet (currently in stage 3) so you must use a transpiler like Babel to handle it.
The value of this
within method
is the class A
because that is what this
points to in the constructor (since arrow functions inherit the context from the scope they are defined in):
class A {
constructor() {
this.method = () => this;
}
}
const instance = new A();
console.log(instance.method() === instance); // true
Defining a regular (non-arrow function) method on the class creates a method on the class prototype (not instance) but sets no rules on what this
will be (since this
is dynamic in JS and depends on how a function is called, not how it's defined).
class A {
method() {}
}
console.log(new A().method === A.prototype.method); // true
If methods defined in either of these ways are called on the class instance (via the .
), as per the rule of how this
is bound when a function is called as a method of an object, this
will point to the class instance in both cases:
class A {
constructor() {
this.methodOnInstance = () => this;
}
methodOnPrototype() { return this; }
}
const instance = new A();
console.log(
instance.methodOnInstance() === instance.methodOnPrototype(), // true
instance.methodOnPrototype() === instance // true
);
One major difference between the two method declarations above is that the instance method has this
always fixed to the class instance while the class (prototype) method does not (we can change it by using Function.prototype.apply or Function.prototype.call)
class A {
constructor() {
this.methodOnInstance = () => this;
}
methodOnPrototype() { return this; }
}
const instance = new A();
console.log(
instance.methodOnInstance() === instance.methodOnPrototype(), // true
instance.methodOnPrototype.call('new this') === 'new this' // true
);
A common occurrence where the this
changes is within an event handler, where the event handler calls the function passed into it and binds the context to the element on which the event happened (so overrides the value of this
to be the element that was clicked or whatever the event was)
This happens in React as well for all (synthetic) DOM event handlers.
Therefore, if we want our method's context to always point to the instance of the React component, we can use the instance method.
Another way of restricting the context but not using the special instance method syntax that requires Babel is to directly create an instance method ourselves by creating a new function from the class (prototype) method with a bound context (using Function.prototype.bind):
class A {
constructor() {
this.methodOnInstance = this.methodOnPrototype.bind(this);
}
methodOnPrototype() { return this; }
}
const instance = new A();
console.log(
instance.methodOnInstance() === instance.methodOnPrototype(), // true
instance.methodOnPrototype() === instance // true
);
This allows us to arrive to the same result as using the special instance method syntax but with the currently available tools (ES2017 and under).
If for some reason we want a method that is always bound to something that is not an instance of the class, we can do that as well:
class A {
constructor() {
this.method = this.method.bind(console);
}
method() { return this; }
}
const instance = new A();
console.log(
instance.method() === console // true
);
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With