How To Handle Events in React - Different Way vs Best Way?

In the Facebook docs, you’ll see event handling done like this:
// option 1
class Thing extends React.Component {
  constructor() {
    this.handleSmthng = this.handleSmthng.bind(this)
  }
  render() {
    <input onChange={this.handleSmthng}/>
  }
  handleSmthng(e) {
    // ...
  }
}
ES6 classes won’t automatically give this scope to handleSmthng, and since you’ll usually want to call this.setState or perhaps invoke another method in the component, the “official” convention is to bind all the event handlers all the time in constructor. This works, but can quickly feel like boilerplate code.
// option 2
class Thing extends React.Component {
  render() {
    <button onClick={() => this.handleSmthng('foo')}>
      ADD
   </button>
  }
  handleSmthng(arg1) {
    // ...
  }
}
It will pass this context to handleSmthng and it avoids boilerplate code in the constructor. Heck, there’s no state in this component so you don’t even need a constructor! I think the motivations for this approach are right… but there’s a slight performance cost. Using an arrow function will always create a new reference in JavaScript which, in turn, increases memory usage for your apps. While memory is cheap in JavaScript, renders are costly in React. When you pass arrow functions to child components, your child component will indiscriminately re-render since (as far as it’s concerned) that arrow function is new data.

There’s a much cleaner way to write event handlers that
1) avoids boilerplate and
2) doesn’t cause extra re-renders: property initializer syntax!
It’s a fancy name, but the idea is really simple… just use arrow functions to define your event handlers. Like this:
class TodoApp extends React.Component {
  render() {
    return (
      <div>
        <button onClick={this.handleClick}>
          ADD
        </button>
        <input onChange={this.handleInput}/>
      </div>
    );
  }
  handleClick = () => {
    // "this"
  }
  handleInput = (e) => {
    // "this", "e"
  }
}
You defined two handlers, and it’s looking really nice. No boilerplate. Easy to read. Easy to re-factor… if you want to pass arguments:
class TodoApp extends React.Component {
  render() {
    return (
      <div>
        <button onClick={this.handleClick}>
          ADD
        </button>
        <input onChange={this.handleInput}/>
        {
          this.state.todos.map((item) => {
            return (
              <li onClick={this.handleRemove(item.id)}>
                {item.text}
              </li>
            );
          });
        }
       {
    // "this"
  }

  handleInput = (e) => {
    // "this", "e"
  }

  handleRemove = (id) => (e) => {
    // "this", "e", "id"
  }
}
You can pass arguments without using bind in your render methods, or your constructor! Everything looks really spick and span.
Source: A New Way to Handle Events in React

Comments

Popular Posts