ZYinMD
ZYinMD

Reputation: 5059

In a React Component, what's the difference between foo(){} and bar = () => {} and when should I use which?

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

Answers (4)

xyhhx
xyhhx

Reputation: 6664

Essentially, there is no difference.

This has nothing to do with React, though.


Arrow functions

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
}

If you have only 1 param, you don't need the parantheses:

function foo (param) {
    // do something
}

// becomes

var foo = param => {
    // do something
}

If there is only 1 expression, and the result is returned, you can omit the {} too!

function foo (param) {
    returns param * 2
}

// becomes

var foo = param1 => param * 2

this is not not updated

In 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)


JS Classes

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)

You can use 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

Felix Kling
Felix Kling

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

Charlie Martin
Charlie Martin

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

Mihai Alexandru-Ionut
Mihai Alexandru-Ionut

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

Related Questions