10

When creating a React class, which is preferable?

export default class Foo extends React.Component {
  constructor (props) {
    super(props)
    this.doSomething = this.doSomething.bind(this)
  }

  doSomething () { ... }
}

or

export default class Foo extends React.Component {
  doSomething = () => { ... }
}

A coworker of mine thinks that the latter causes memory problems because babel transpiles the code to capture this inside the closure, and that reference will cause the instance to not be cleaned by GC.

any thoughts about this?

Bergi
  • 630,263
  • 148
  • 957
  • 1,375
davegri
  • 2,206
  • 2
  • 26
  • 45
  • How would what Babel does for `=>` functions be any different than what `.bind()` does? – Pointy Dec 29 '16 at 14:36
  • Using fat arrow functions saves this inside the closure – davegri Dec 29 '16 at 14:48
  • Yes. What do you suppose `.bind()` does? – Pointy Dec 29 '16 at 15:01
  • I'm looking at the transpiled code and it dosent look identical, I'm not really sure what its doing though – davegri Dec 29 '16 at 15:15
  • The point is that one way or the other, the contextual value of `this` has to be saved *somewhere*. Before `.bind()` became part of the language it was commonly implemented with a closure, and there's no reason to suspect it's not basically the same now (though with some added behaviors). – Pointy Dec 29 '16 at 15:47
  • Possible duplicate of [React.js ES6 avoid binding 'this' to every method](http://stackoverflow.com/questions/32192682/react-js-es6-avoid-binding-this-to-every-method) – lux Dec 29 '16 at 15:55

3 Answers3

9

The public class field syntax (so doSomething = () => {...}) is not yet part of ECMAScript but it is doing well and I am pretty confident that it will get there.

So using this syntax forces you to transpile, but it brings advantages:

  • clear, concise syntax for expressing this binding
  • future proof for when browsers support this
  • not concerned with implementation

For me, this is a clear win. In most cases, you don't even need a constructor(props), saving you from that boilerplate super call.

If the Babel implementation would cause memory leaks, you can be sure those would have been found and fixed quickly. You are more likely to create leaks yourself by having to write more code.

w00t
  • 17,944
  • 8
  • 54
  • 62
3

Binding in the render function causes new functions to be created on every render, this means the diffing algoritm thinks there are changes. When you bind in the constructor this does not happen.

Here you can see the compiled difference for binding with arrow and binding in the constructor: https://babeljs.io/repl/#?babili=false&evaluate=true&lineWrap=false&presets=es2015%2Creact%2Cstage-2&experimental=true&loose=false&spec=false&code=class%20x%20extends%20React.Component%20%7B%0A%20%20constructor%20(props)%20%7B%0A%20%20%20%20super(props)%3B%0A%20%20%20%20%0A%20%20%20%20this.onChange%20%3D%20this.onChange.bind(this)%3B%0A%20%20%7D%0A%20%20%0A%20%20onChange%20()%20%7B%20console.log(%27change%20x%27)%3B%20%7D%0A%7D%0A%0Aclass%20y%20extends%20React.Component%20%7B%0A%20%20onChange%20%3D%20()%20%3D%3E%20%7B%20console.log(%27change%20y%27)%3B%20%7D%0A%7D

Klaasvaak
  • 5,634
  • 15
  • 45
  • 68
  • I'm not asking about binding in the render, I'm asking about using fat arrow vs binding in constructor – davegri Dec 29 '16 at 14:43
  • This is actually valuable information, I don't understand why it was downvoted. – João Vilaça Aug 30 '17 at 10:40
  • This is the correct answer. Using fat arrow functions can cause memory leaks in the form of detached DOM nodes from my experience. Much nicer to look at but there is a significant memory cost here. – Hunt Burdick Dec 27 '18 at 18:12
0

The link here clearly highlights that officially it's safe to "Bind methods in constructor" rather than using the arrow function as a short code to achieve event binding.

Here is the link: https://reactjs.org/docs/react-without-es6.html#autobinding for reference.

v kay
  • 57
  • 8