The only way I know of is to create a new React Component which takes the value and the event handler as props.
This way, the handler as a function remains static, and since the value is passed down separately (in its own prop) you don't have any functions being re-instanciated. Because you don't bind anything nor create a new function each time.
Here's an example:
We have two buttons. The first one prints the current state variable value and the other increments it by one.
Normally, if we had done this with onClick={() => this.print(this.state.value)} we would get a new instance of this function, each time the MyApp component would re-render. In this case, it would re-render each time we increment the value with the setState() inside this.increment.
However, in this example, no new instance of this.print happens because we are only passing its reference to the button. In other words, no fat arrow and no binding.
In the <Button /> component, we have a <button> to which event handler we pass a reference to a function - just like we did in <MyApp />. However, here we know exactly what to pass to the function. As such, we have myHandler trigger this.props.handler(this.props.value).
class MyApp extends React.Component {
constructor() {
super();
this.state = {
value: 0
};
}
print = (value) => {
console.log(value);
}
increment = () => {
// This will trigger a re-render, but none of the functions will be reinstanciated!
this.setState((prevState) => ({value: prevState.value + 1}));
}
render() {
// Note that both handlers below are passed just the references to functions. No "bind" and no fat arrow.
return(
<div>
<Button handler={this.print} value={this.state.value}>Print</Button>
<button onClick={this.increment}>Increment</button>
</div>
);
}
}
class Button extends React.Component {
// Clicking the button will trigger this function, which in turn triggers the function with the known argument - both of which were passed down via props.
myHandler = () => this.props.handler(this.props.value);
render() {
// Note again that the handler below is just given the reference to a function. Again, not "bind" nor fat arrow.
return(
<button onClick={this.myHandler}>{this.props.children}</button>
);
}
}
ReactDOM.render(<MyApp />, document.getElementById("app"));
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react-dom.min.js"></script>
<div id="app"></div>
Though quite tedious, it is an effective solution. That being said, even if you do create a new function each time you render, the performance implications are minimal. From the official docs:
The problem with this syntax is that a different callback is created each time the LoggingButton renders. In most cases, this is fine.