React.js ES6 avoid binding 'this' to every method
Solution 1:
You can use class fields to do the binding outside the constructor. They look like the following:
class Foo extends React.Component {
handleBar = () => {
console.log('neat');
};
handleFoo = () => {
console.log('cool');
};
render() {
return (
<div
onClick={this.handleBar}
onMouseOver={this.handleFoo}
/>
);
}
}
Class fields are supported experimentally by Babel via its class properties transform, but they are still "experimental" because they are a Stage 3 Draft (not yet in a Babel preset).
You will need to do the binding manually until ES7 or until enabling the feature in Babel, however. This topic is covered briefly in Babel's blog post on React on ES6+.
Solution 2:
Another alternative is to use decorators. You declare a getter on the prototype, and on first access for an instance it defines an own property with a bound version of that function.
But there's a catch! In development it won't replace the property, it'll bind on every access. This means you don't break react-hot-loader. At least for me, that's pretty important.
I created a library, class-bind, that provides this.
import {bound} from 'class-bind';
class App {
constructor(){
this.foo = 'bar';
}
@bound
returnsFoo(){
return this.foo;
}
render(){
var returnsFoo = this.returnsFoo;
return (
<div>
{returnsFoo()} === 'bar'
</div>
);
}
}
Decorators too unstable for you? You can bind everything or some things with the same benefits.
import {bind, bindAll} from 'class-bind';
bind(App.prototype, 'returnsFoo');
// or
bindAll(App.prototype);
Solution 3:
Ssorallen's suggestion is great but if you want another way there is:
class AppCtrlRender extends Component {
binder(...methods) { methods.forEach( (method) => this[method] = this[method].bind(this) ); }
render() {
var isMobile = this.state.appData.isMobile;
var messages = this.state.appData.messages;
return (
<div id='AppCtrlSty' style={AppCtrlSty}>
React 1.3 Slider
<br/><br/>
<div className='FlexBoxWrap'>
<Slider isMobile={isMobile}/>
<JList data={messages}/>
</div>
</div>
);
}
}
var getAppState = function() {
return {
appData: AppStore.getAppData()
};
};
export default class AppCtrl extends AppCtrlRender {
constructor() {
super();
this.state = getAppState();
this.binder('appStoreDidChange');
}
componentDidMount() {
var navPlatform = window.navigator.platform;
Actions.setWindowDefaults(navPlatform);
}
componentWillMount() { AppStore.onAny(this.appStoreDidChange); }
componentWillUnmount() { AppStore.offAny(this.appStoreDidChange); }
appStoreDidChange() { this.setState(getAppState()); }
}
You can add any number of methods to this.binder('method1', 'method2', ...)