Reputation:
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)} />
Upvotes: 15
Views: 6327
Reputation: 562
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.
Upvotes: 6
Reputation: 637
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
Upvotes: 1
Reputation: 780
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.
Upvotes: 0
Reputation: 2614
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.
Upvotes: -3
Reputation: 816394
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.
Upvotes: 0
Reputation: 281676
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
Upvotes: 8