Passing an arrow function vs passing the function in React

一世执手 提交于 2019-12-10 06:31:18

问题


Say i have a function:

handleChange = (e) => {
  this.setState({ [e.target.id]: e.target.value });
}

What is the difference between the following:

1.

<FormControl value={this.state.password} onChange={this.handleChange} />

2.

<FormControl value={this.state.password} onChange={(e) => this.handleChange(e)} />

Thanks!


回答1:


The second case an anonymous function is created which executes the handleChange method and and thereby providing it the context.

Everytime the React component renders, a new function is created in the second and not in the first case since the same reference of handleChange method is being provided to the handler.

You might also want to look at how arrow function in render achieve context binding




回答2:


Assuming your event handler is written like so in your class

handleChange = (e) => {
  this.setState({ [e.target.id]: e.target.value });
}

Let us go to the first example that you have mentioned.

<FormControl value={this.state.password} onChange={this.handleChange} />

Over here, for every change you are passing the memory reference of the handleChange function, and to it the event object is being passed.

Going to the second method.

<FormControl value={this.state.password} onChange={(e) => this.handleChange(e)} />

Here you are creating a new anonymous function, which takes the event object as a parameter, every time an event change occurs. This drastically increases garbage collection if you have large list items.Adding an arrow function in this case is redundant as the context is already bound due to the way you wrote you handleChange method initially. As a perf tip, if you are using arrow functions in your classes, use option 1 for event handlers.




回答3:


We can bind our event handlers in class constructor:

we can now access to this inside the event handle

class MyClass extends Component {
  constructor(props) {
    super(props)
    this.handleChange = this.handleChange.bind(this)
  }
  handleChange(){
   //you can now access "this" inside handlechange
  } 

}

Looks fine. When we add more event handlers to our class, code should look similar to this:

import React, { Component } from 'react'
import { MyInput, MyAnotherInput } from 'myInputs'

class MyComponent extends Component {
  constructor(props) {
    super(props)
    this.handleChange = this.handleChange.bind(this)
    this.handleClick = this.handleClick.bind(this)
    this.handleKeyPress = this.handleKeyPress.bind(this)
  }

  handleChange(e) {
    e.preventDefault()
  }

  handleClick(e) {
    e.preventDefault()
  }

  handleKeyPress(e) {
    e.preventDefault()

    if (e.nativeEvent.keyCode === 13) {
      console.log('This is enter!')
    }
  }

  render() {
    return (
      <div>
        <MyInput
          onChange={ this.handleChange }
          onClick={ this.handleClick }
          onKeyPress={ this.handleKeyPress }
        />
        <MyAnotherInput
          onChange={ this.handleChange }
          onClick={ this.handleClick }
          onKeyPress={ this.handleKeyPress }
        />
      </div>  
    )
  }
}

This is, what we can do with Babel compiler with es2015 as preset configuration.

Event handlers with arrow functions

As you have probably seen, when we create event handler method, we always need to add this to constructor, to bind this. Quite tiresome. To be honest, there is no sense to create constructor method only for binding your methods. There should be another solution, and there is.

All what you need is to install stage-1 Babel preset and use arrow functions. If you don’t know, how to do this, go to Babel documentation, it’s very good.

In our case instead of binding methods to this we can writ something like this:

render() {
   return(<MyInput onChange={ (e) => this.handleOnChange(e) } />)
}

We have created new anonymous function, which automatically bind this, that’s why we don’t need to use .bind() method. We have still the same methods in class, and new arrow functions as wrappers in callbacks properties.

This is still not perfect solution, because we need to update parameters in arrow function wrappers and we create new instances each time when render method is triggered. Arrow functions in React properties are also not great idea.




回答4:


Using arrow function in render may cause some performance issues.

I'd suggest you to use arrow function in class property, but you must use stage-2 features.

Here you'll find a nice comparison between the options:

https://medium.freecodecamp.org/react-binding-patterns-5-approaches-for-handling-this-92c651b5af56




回答5:


In the first case you are using handleChange as event handler.

In the second case you are using a new function as event handler, which in turn calls handleChange.

The difference is that there will be two function calls in the second example. Otherwise they are the same.

In other words: there is no need to use the second form, and it can even be disadvantageous for rerendering.




回答6:


When handling an event in JavaScript, the this context out of the box can be very confusing, you can read more about it in this excellent writeup.

Back to your question, the first way onChange={this.handleChange} does not guarantee the this context in handleChange() would always be the same component instance, in many cases, this would refer to the FormControl instance that emits the onChange event.

The second way uses arrow syntax, it would guarantee this would always be the React component instance that handles the event.

In short, using arrow syntax for event handling is preferred in React component classes because it guarantees a consistent this context.



来源:https://stackoverflow.com/questions/48305194/passing-an-arrow-function-vs-passing-the-function-in-react

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!