13

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} />
<FormControl value={this.state.password} onChange={(e) => this.handleChange(e)} />
  • So, as I understand, the problems with 'this' are solved by using an arrow function in the declaration of handleChange, so adding the anonymous function is not necessary. Is this correct? –  Jan 17 '18 at 16:41

6 Answers6

8

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

Shubham Khatri
  • 270,417
  • 55
  • 406
  • 400
6

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.

Nitish Phanse
  • 552
  • 1
  • 9
  • 16
1

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

Saeed Seyfi
  • 637
  • 5
  • 18
  • 1
    A link to a solution is welcome, but please ensure your answer is useful without it: [add context around the link](//meta.stackexchange.com/a/8259) so your fellow users will have some idea what it is and why it’s there, then quote the most relevant part of the page you're linking to in case the target page is unavailable. [Answers that are little more than a link may be deleted.](//stackoverflow.com/help/deleted-answers) – Suraj Rao May 17 '18 at 07:14
0

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.

Felix Kling
  • 795,719
  • 175
  • 1,089
  • 1,143
  • And the second example creates a new function on every render, right? – nem035 Jan 17 '18 at 16:02
  • 1
    Good point. I was focusing on the execution of the function only. – Felix Kling Jan 17 '18 at 16:03
  • The second method creates a wrapper function that calls `handleChange`. – J.D. Pace Jan 17 '18 at 16:04
  • The second case is useful in a lot of cases, and its used even in react's official guides, it's not useful here but that pattern is useful – Marcell Monteiro Cruz Jan 17 '18 at 16:27
  • @MarcellMonteiroCruz: sure, I’m only talking about the OP’s situation. – Felix Kling Jan 17 '18 at 16:46
  • @MarcellMonteiroCruz although the pattern is useful , it should be avoided as much as possible because of the fact that a new function is created on every render, I wrote an answer on ways to avoid it some time back https://stackoverflow.com/questions/45053622/how-to-avoid-binding-inside-render-method/45053753#45053753 – Shubham Khatri Jan 17 '18 at 16:46
  • @ShubhamKhatri thx for the links, but is this really a problem ? how much impact on performance will it have ? – Marcell Monteiro Cruz Jan 17 '18 at 18:08
  • @MarcellMonteiroCruz Not really sure on the statistics point of it but as your application grows a significant amount of memory consumption will start happening which can really be avoided – Shubham Khatri Jan 17 '18 at 18:12
0

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.

Prakash Naidu
  • 742
  • 2
  • 7
  • 17
-3

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.

Tianzhen Lin
  • 2,404
  • 1
  • 19
  • 19