No more need for method pre-binding, looks like!

Since ES2015 classes do not auto-bind their methods to the class the same way React.createClass does, it’s been suggested that people pre-bind their methods in the constructor:

class Thing extends React.Component {
  constructor(props) {
    super(props);
    
    this.func1 = this.func1.bind(this);
    this.func2 = this.func2.bind(this);
  }
  
  func1(event) {}
  
  func2() {}
}

It seems that Meteor now supports class properties, so you can now simply do this:

class Thing extends React.Component {
  func1 = (event) => {};
  func2 = () => {};
}

And func1 and func2 will automatically have this context properly available. We’ve come full circle! :wink:

8 Likes

What? When did that happen?

No idea! I just discovered it on the new StackOverflow Docs for React. I knew about statics for things like propTypes, but didn’t know about methods too.

It’s ES2016 stage 1.

I wonder if that transpiles with stock meteor. I use .babelrc for such extras.

This is all because of in-class properties and the scope of the arrow-functions.

1 Like

If using Babel, you just need to add class properties to your babelrc. https://babeljs.io/docs/plugins/transform-class-properties/

1 Like

Yeah, turns out there’s a bit of setup, actually. I thought it was automatic, but it’s not. Still, thanks to .babelrc, it’s easy to make this change.

I’m currently learning React. Can someone explain this behavior (the need of writing this.func = this.func.bind(this) in the constructor), please? The only rationale for this that I’ve found so far comes from their blog https://facebook.github.io/react/blog/2015/01/27/react-v0.13.0-beta-1.html#autobinding:

React.createClass has a built-in magic feature that bound all methods to this automatically for you. This can be a little confusing for JavaScript developers that are not used to this feature in other classes, or it can be confusing when they move from React to other classes.

Therefore we decided not to have this built-in into React’s class model. You can still explicitly prebind methods in your constructor if you want.

But I don’t buy it. Why force all of us to write this extra piece of code?

If you have <div onClick={this.tick} />, when using a class, React calls the tick function using a function invocation pattern. That means tick’s context isn’t going to be the component’s instance.

Why force all of us to write this extra piece of code?

This is what happens when you don’t design for humans. You end up making developers perform needless ceremonies.

2 Likes

So there’s really no good reason for it? Just a design “mistake”? And what’s keeping them from “correcting” it? Does this refer to something else by default, so they don’t want to break backward compatibility?

There is a reason… you (and I) just don’t think it’s a good one. It’s not a design mistake, just a design decision. Correcting it? There is nothing to correct based on the way they think it should behave.

1 Like

Sorry for being stupid, but what’s the reason? Why not use the component instance as the context when calling the event handler? I only see benefits, but if they don’t think it’s a good idea I guess there must be a drawback, right? What’s the drawback?

The reason is that without doing/adding anything, with JavaScript, the events call the functions with their context, not the component instance as context. React used to add that “something” (bind functions to the component’s instance) but they decided to go against it when using JS classes. So now you have to bind the functions yourself.

I understand that this is the reason I need to write the binding myself, what I don’t understand is why Facebook has designed it this way. They must have a reason for it? The only explanation I can find is This can be a little confusing for JavaScript developers that are not used to this feature in other classes, or it can be confusing when they move from React to other classes. Therefore we decided not to have this built-in into React’s class model, but I don’t buy it. If this is the only reason, I think it’s a poor decision.

I found the explanation This change emphasized that React is JavaScript - and React authors don’t want to escape this truth. (source). I find that reason acceptable, but I don’t like it.

I think I support that decision in a way that I support Meteor aligning with stock Javascript. Because the other end of discussion is a probably very loud “you are locking us in” objection, and frankly, I like being able to think in terms of javascript and having to read minimum amount of api docs from the framework while not worrying about the framework hijacking some default language behavior.

1 Like

I don’t think that’s valid. As it is now, you’re forcing all programmers to write this.func = this.func.bind(this) when they are creating a react component. If we would have this behavior by default, third-party programmers would instead need to write a similar line in their classes (alternatively we would need to write onClick={this.tick.bind(this)}).

Given that react programmers always use reacts components and only some times use third-party objects, it makes most sense to me to facilitate creation of react components.

I prefer stateless components if possible, so I don’t have to worry about this :wink: (no pun intended)

Well that’s partially correct because there are other ways of doing the same. Like:

  • using arrow functions to bind the tick function to the component instance
  • using ::this.tick() syntax from ES7
  • using a prebind helper like the one @ffxsam published

But, autobinding means, you cannot revert this behavior for cases when you actually don’t want that to happen.

Furthermore, there are other libraries out there that are api compatible with react, such that you can continue using the same classes, only switching your rendering engine from react to vue, preact, deku etc. Had prebinding been the case, it would have meant a vendor lock in due to the hijacking of a standard Javascript behavior.

1 Like