junlin
junlin

Reputation: 2035

What is the best way to write event handler in React?

I had read the article about handle events in react with arrow functions. And the final way in that article is not likely the best because of re-render issue.

e.g.

class Example extends React.Component {
  handleSelect = i => e => {
    console.log(i)
  }

  render() {
    return {this.state.language.map(item, i) => (
      <ListItem 
        ...
        onPress={this.handleSelect(i)}  // re-render sub component every time the Example render() because of the annoymous function
      />
    )}
    
  }
}

I wonder which way is the best to write event handler in React?

Upvotes: 3

Views: 655

Answers (1)

Rico Kahler
Rico Kahler

Reputation: 19222

In order to get the best performance out of React, you need to minimize the number of objects that are being created during renders. And as a reminder a function declaration (e.g. function myFunc or const func = () => {}) creates an object.


I would say your code has an unsolvable issue because you're creating a new instance of the inner function when handleSelect is invoked:

handleSelect = i => e => {
  console.log(i)
}

I'll rewrite this using the function notation because it's a bit more clear what happening (but I prefer arrow functions in practice):

handleSelect = function (i) {
  return function (e) {
    console.log(i);
  }
}

The issue here is the with each render when you invoke handleSelect it creates a brand new inner function (i.e. function (e) {/* ... */}).


I mentioned that your code has an unsolvable issue because there is no way to split up your curried handleSelect function because you're passing the index i that's created inside the render function. Because that state doesn't exist anywhere else, you have to create a new function to close-over it every time and that's okay.

I would even refactor your code like so:

class Example extends React.Component {
  // as @RickJolly mentioned, this method doesn't have to be arrow
  handleSelect (i) {
    console.log(i)
  }

  render() {
    return {this.state.language.map(item, i) => (
      <ListItem 
        ...
        onPress={() => this.handleSelect(i)}
    )}

  }
}

If you have to create a new function every time, then you might as well inline it vs returning a function. That's preference though.


Edit

As @RickJolly mentioned, if your method doesn't use this then it shouldn't be an arrow function.

From his comment:

since you're calling () => this.handleSelect(i) via an arrow function, this is bound to the this of the enclosing context [which is the class pointer]

Upvotes: 4

Related Questions