Reputation: 5059
Babel is doing its magic, which makes me very confused about what's going on.
What's the difference between foo and bar in this react Component? And when should I use which?
class MyComponent extends Component {
foo() {
//...
}
bar = () => {
//...
}
}
(My own guess is foo is in the prototype, and bar is in the constructor? Anyways, I don't know what I'm talking about)
Upvotes: 3
Views: 1672
Reputation: 6664
Essentially, there is no difference.
This has nothing to do with React, though.
Arrow functions are a relatively new feature added to Javascript that give you a way of defining functions in a more concise way.
function foo (param1, param2, etc) {
// do something
}
// becomes
var foo = (param1, param2, etc) => {
// do something
}
function foo (param) {
// do something
}
// becomes
var foo = param => {
// do something
}
{}
too!function foo (param) {
returns param * 2
}
// becomes
var foo = param1 => param * 2
this
is not not updatedIn an arrow function, you don't get a new this
- it is the same as in the parent block. This can be useful in some cases (when using setTimeout
, for example)
In ES6 we can also use the class
keyword to define "classes" in Javascript. They still use prototype, though!
function Something (foo) {
this.bar = foo;
}
Something.prototype.baz = function () {
return baz * 2
}
// becomes
class Something {
constructor(foo) {
this.bar = foo;
}
baz () {
return baz * 2
}
}
So the constructor is done in constructor()
and all the following methods are added to the Prototype. It's nothing but syntactic sugar (but kinda does some of the Prototype heavy lifting for you)
extends
!class SomethingElse extends Something {
constructor(foo, lol) {
this.lol = lol
// Use super() to call the parent's constructor
super(foo)
}
baz () {
return baz * 2
}
}
Upvotes: 0
Reputation: 816404
My own guess is foo is in the prototype, and bar is in the constructor?
That's exactly right.
foo() {}
in this context is a method declaration and the value gets assigned to the prototype. It's equivalent to
MyComponent.prototype.foo = function() {};
bar = ... ;
on the other hand is a class field. This is a shorthand notation for assigning properties to the instance in the constructor:
constructor() {
this.bar = ... ;
}
And because of how arrow functions work, using class fields with arrow functions basically lets you create "bound" methods.
More on arrow functions: Arrow function vs function declaration / expressions: Are they equivalent / exchangeable?
And when should I use which?
The tl;dr is: Use class field + arrow function when you need a bound function.
When do you need a bound function? Whenever you want this
inside the function to refer to a specific value but you don't control how the function is called.
That's mostly the case for event handlers (i.e. functions that are passed to other functions / components) that need to access the component instance (e.g. call this.setState
or access this.props
/this.state
).
You don't have to use it though, you could also bind the method when you need to. However, binding a method only once in the constructor is ideal for React components so that, if the method is passed as event handler, always the same function object is passed.
As noted in another answer, this is not related to React at all. Class fields are likely officially integrated into the language this year.
Upvotes: 7
Reputation: 8406
foo
is an instance method of class MyComponent
. While bar
is an instance property of class MyComponent
(that happens to be assigned an anonymous function).
It might make more sense to see it used in the traditional sense...
class MyComponent {
// instance property
someProperty = 42;
// instance method
someMethod() {}
}
So why use an instance property instead of an instance method?
Instance methods in javascript must be called within the class scope to inherit the class context (this
)...
class MyComponent {
// instance method
someMethod() {
const value = this.state.value // ERROR: `this` is not defined
}
render() {
return <div onClick={this.someMethod} />
}
}
However, since arrow functions inherit their scope, this
will be available if you use an arrow function instead
class MyComponent {
// instance method
someProperty = () => {
const value = this.state.value // this works!
}
render() {
return <div onClick={this.someProperty} />
}
}
Upvotes: 1
Reputation: 48357
In the second example bar
is an arrow function.
Until arrow
functions, every new
function defined its own this
value.
For instance, this
can be a new object in the case of a constructor.
function Person(age){
this.age=age;
console.log(this);
}
let person=new Person(22);
Or this
can points to the base
object if the function created can be accessed like obj.getAge()
.
let obj={
getAge:function(){
console.log(this);
return 22;
}
}
console.log(obj.getAge());
An arrow
function does not create its own this
, it's just used the this
value of the enclosing
execution context
. In the other hand, arrow
function uses this
of parent scope.
Upvotes: 1