classMyComponentextendsReact.Component {render() {// badreturn <ButtononClick={() =>console.log('I was clicked')} />; }}
The problem with the above code is that every time the render method of our MyComponent component is called, a new function will be created for our onClick handler. While this might sound like a premature optimization, there are legitimate performance concerns at Shopify's scale.
Worse yet, there is also another side-effect of creating a new function on every single render: If our Button component were implemented using PureComponent, it would effectively need to update on every single render. Since the onClick handler wouldn't be referentially equal to the previous one, it would think its props have changed.
Solution
Binding the handler in our component's constructor and passing the handler by reference:
There is also an @autobind decorator you can import from shopify/javascript-utilities to achieve the same effect. Decorators aren't part of the official EcmaScript spec yet, but you can use a babel transform to add support for them, or, if you're using TypeScript, they're already supported out of the box.
One problem you might run into with this approach is when mapping over an array to render a list of elements.
classItemListextendsReact.Component { @autobindrenderItem(item, index) {return ( <li> Item ##{index} <buttononClick={this.handleClick}>Remove</button> </li> ); } @autobindhandleClick() {// How can you tell which item was clicked from here without creating an inline lambda above? }render() {return <ul>{this.props.items.map(this.renderItem)}</ul>; }}
In this case, the solution would be to refactor our component to split out the item rendering logic into a separate component: