6

I have this in my JSX:

<Options options={options} onOptionSelect={this.onOptionSelect.bind(this)} />

However, I swear I've seen some fanciness to negate the need for .bind when passing callback methods down to child React components, am I right?

benhowdle89
  • 36,900
  • 69
  • 202
  • 331
  • 1
    Possible duplicate of [can i use ES6 fat arrow in class methods?](http://stackoverflow.com/questions/31362292/can-i-use-es6-fat-arrow-in-class-methods) – Bergi Dec 02 '15 at 18:16
  • @Bergi Is it a duplicate? I'm not asking how can I use fat arrows in class methods, but what can I use to achieve X. It just turned out fat arrows was the answer... – benhowdle89 Dec 02 '15 at 18:17
  • yeah, the question's title isn't exactly the same, but arrow functions seemed to be what you were looking for. Would you think "[React.js ES6 avoid binding 'this' to every method](http://stackoverflow.com/q/32192682/1048572)" is a better duplicate? – Bergi Dec 02 '15 at 18:24
  • 1
    In react.js blog there is mention about autobinding https://facebook.github.io/react/blog/2015/01/27/react-v0.13.0-beta-1.html#autobinding – Oleksandr T. Dec 02 '15 at 19:02

2 Answers2

7

You can use an arrow function combined with property initialization.

class Component extends React.Component {
  handleClick = () => {
    console.log(this.props);
  }

  render() {
    return <div onClick={this.handleClick} />
  }
}

Because the arrow function is declared in the scope of the constructor, and because arrow functions maintain this from their declaring scope, it all works. The downside here is that these wont be functions on the prototype, they will all be recreated with each component. However, this isn't much of a downside since bind results in the same thing.

Kyeotic
  • 19,697
  • 10
  • 71
  • 128
  • It would be better if you explicitly put it in the constructor, instead of using that experimental class property thingy :-) – Bergi Dec 02 '15 at 18:17
  • 1
    @Bergi Why is that better? Op specifically mentioned ES7 and babel, which this works with. – Kyeotic Dec 02 '15 at 18:18
  • a) less confusion - you wouldn't need to mention that it is in the constructor's scope b) all "ES7" are currently proposals only and the babel plugins are experimental – Bergi Dec 02 '15 at 18:22
  • There is no guarantee that arrow functions in class properties will continue to autobind like the proposal currently supports, for instance. – loganfsmyth Dec 02 '15 at 18:56
  • That may be true, but the OP was specifically asking for a solution without `bind`. This is the only one I know of. Also, you can configure Babel to run with these, even if its removed from the spec. – Kyeotic Dec 02 '15 at 19:00
  • For those using only ES2015 but who want to do this as well, since this is experimental, you need to add this plugin to be able to use this functionality (because it relies on how ES7 scopes property initializers, not the arrow function itself): http://babeljs.io/docs/plugins/transform-class-properties/ – Sia Jul 05 '16 at 20:48
0

You can bind all the functions of a component using ES2015 class syntax with this autoBind helper function:

class Component extends React.Component {
  constructor(props) {
    super(props);
    autoBind(this);
  }

  onOptionSelect() {
    // do stuff
  }

  render() {
    return <Options options={options} onOptionSelect={this.onOptionSelect} />;
  }
}

function autoBind(obj) {
    getAllMethods(obj.constructor.prototype)
        .forEach(mtd => {
            obj[mtd] = obj[mtd].bind(obj);
        });
}

function getAllMethods(obj) {
    return Object.getOwnPropertyNames(obj).filter(key => typeof obj[key] == "function");
}

Note that Component doesn't have to use methods defined with arrow functions.

romseguy
  • 1,535
  • 13
  • 17