How to avoid bind or inline arrow functions inside render method
First: A simple solution will be to create a component for the content inside a map function and pass the values as props and when you call the function from the child component you can pass the value to the function passed down as props.
Parent
deleteTodo = (val) => {
console.log(val)
}
todos.map(el =>
<MyComponent val={el} onClick={this.deleteTodo}/>
)
MyComponent
class MyComponent extends React.Component {
deleteTodo = () => {
this.props.onClick(this.props.val);
}
render() {
return <div onClick={this.deleteTodo}> {this.props.val} </div>
}
}
Sample snippet
class Parent extends React.Component { _deleteTodo = (val) => { console.log(val) } render() { var todos = ['a', 'b', 'c']; return ( <div>{todos.map(el => <MyComponent key={el} val={el} onClick={this._deleteTodo}/> )}</div> ) } }
class MyComponent extends React.Component { _deleteTodo = () => { console.log('here'); this.props.onClick(this.props.val); } render() { return <div onClick={this._deleteTodo}> {this.props.val} </div> } } ReactDOM.render(<Parent/>, document.getElementById('app'));
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react.min.js"></script><script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react-dom.min.js"></script><div id="app"></div>
Correct use of arrow functions in React
I understand that arrow functions make things more efficient by not
recreating the functions each render similar to how binding in the
constructor works.
This is not true. It depends on where exactly are you using the Arrow function. If Arrow function
are used in render method, then they create a new instance everytime
render is called just like how bind
would work. Consider this example
<div onClick={()=>{this.onClick()}}>Previous</div>
Here each time render is called an anonymous function is created and that function when called, calls this.onClick
.
However consider the case below
onClick = () => {
console.log("Div is clicked")
}
In above case, the arrow function does not recreate function everytime, but binds the context to the React component as An arrow function does not have its own this; the this value of the enclosing execution context is used.
once when the class is instantiated. This is similar to how binding works is constructor
. This is a part of proposed class fields for arrow functions
and it isn't a ES6 feature,
To understand what you wish to ask, you must know that a function gets its context from where it is called. Check this question
for more understanding.
In your case, you have used Arrow function
to define prevItem
and hence it gets the context of the enclosing React component.
prevItem = () => {
console.log("Div is clicked")
}
render(){
return (
<SecondClass prevItem={this.prevItem} />
)
}
Now in its child, even if you call prevItem
with any custom context, using bind or arrow function
, prevItem
when executed in parent i.e Main.js
will get the context of its enclosing React component. And since you just wish to execute prevItem function and do not want to pass any data to this from the child, writing
<ThirdClass type="prev" onClick={()=>this.props.prevItem()} />
and
<div onClick={()=>{this.props.onClick()}}>Previous</div>
is simply useless and will only add to performance implication since new functions are created in SecondClass
and ThirdClass
everytime. You simply don't need to have these functions defined as arrow function and could just write
<ThirdClass type="prev" onClick={this.props.prevItem} />
and
<div onClick={this.props.onClick}>Previous</div>
since its already binded in the parent.
Now even if you have to pass some additional data to these function from ThirdClass and SecondClass, you shouldn't directly use Arrow function
or bind in render
. Have a look at this answer on How to Avoid binding in Render method
Why shouldn't JSX props use arrow functions or bind?
Why you shouldn't use inline arrow functions in JSX props
Using arrow functions or binding in JSX is a bad practice that hurts performance, because the function is recreated on each render.
Whenever a function is created, the previous function is garbage collected. Rerendering many elements might create jank in animations.
Using an inline arrow function will cause
PureComponent
s, and components that useshallowCompare
in theshouldComponentUpdate
method to rerender anyway. Since the arrow function prop is recreated each time, the shallow compare will identify it as a change to a prop, and the component will rerender.
As you can see in the following 2 examples - when we use inline arrow function, the <Button>
component is rerendered each time (the console shows the 'render button' text).
Example 1 - PureComponent without inline handler
class Button extends React.PureComponent { render() { const { onClick } = this.props; console.log('render button'); return ( <button onClick={ onClick }>Click</button> ); }}
class Parent extends React.Component { state = { counter: 0 } onClick = () => this.setState((prevState) => ({ counter: prevState.counter + 1 })); render() { const { counter } = this.state; return ( <div> <Button onClick={ this.onClick } /> <div>{ counter }</div> </div> ); }}
ReactDOM.render( <Parent />, document.getElementById('root'));
<script crossorigin src="https://unpkg.com/react@16/umd/react.production.min.js"></script><script crossorigin src="https://unpkg.com/react-dom@16/umd/react-dom.production.min.js"></script><div id="root"></div>
Bind vs Arrow Function when passing onChange props (React)
Since it is only using a reference to the function, we are not causing a re-render each time
You're wrong.
The bind
method returns a new function (so will trigger a re-render).
To avoid re-renders, make use of the useCallback
hook.
Or, since you don't appear to be making use of this
inside myFunction
(otherwise () => myFunction()
would break it), just pass myFunction
itself without creating a new function.
onClick={myFunction}
pass parameters to a javascript function without using an inline function inside jsx
That blog post you have mentioned is at least misleading, and doesn't give sufficient context to understand it's statement (e.g. why you would even use a nested function in that case at all).
Your example (a function component) is fundamentally different to the one in that blog post (a class component).
In your example, it is ok to use a function to "pass" the parameters to the handler.
That is generally inline with common react principles, and it doesn't matter a lot if you are using
an arrow function (const f = () => {};
) or a classic function (const f = function(){};
). (optimizations are still possible.)
What the blog post says, and doesn't say ...
The blog post states that you should "Avoid Arrow Functions", and gives an example.
In that example there is a difference between using a classic and an arrow function, but that isn't the actual problem,
and the blog post doesn't say why you would use an extra function there at all (no matter if classic or arrow function) ?
class MyClass extends React.Component {
addTodo() {}
render() {
return <>
<MyComponent onClick={ () => this.addTodo() /* <-- Why would you even do this ? ... */ } />
<MyComponent onClick={ function(){ this.addTodo() } /* <-- ... even with a classic function ? */ } />
<MyComponent onClick={ this.addTodo } /> /* <-- Recommended. */
</>;
}
}
Of course, you should avoid that extra function, if there is no reason to add it.
What the blog post probably means ...
A common reason to use an extra function there is to capture the this
context of the class. Indeed, here you need to use an arrow function.
In this example, only the arrow function will work (and the alternative), because it captures the this
context of the component:
class MyClass extends React.Component {
myValue = 'some value';
addTodo(){
try { console.log( 'ok, value is:', this.myValue ); }
catch(_){
console.error( 'error: `this` is:', this );
}
}
render() {
const capturedThis = this;
return <>
<button onClick={ () => this.addTodo() } > arrow: works. </button>
<button onClick={ this.addTodo } > no extra function: error. </button>
<button onClick={ function(){ this.addTodo(); } } > classic function: worse error! </button>
<button onClick={ function(){ capturedThis.addTodo(); } } > classic alternative: works. </button>
</>;
}
}
What the blog post missed ...
The captured this
context ("closure") might cause problems. That is probably why the blog post recommends to avoid it.
But the actual recommendation should not be to "avoid arrow functions", but to avoid capturing the this
context in a closure (which is usually done by using an arrow function).
A solution would be to bind the method to the component:
class MyClass extends React.Component {
constructor(props){
super(props);
this.addTodo = this.addTodo.bind(this); // <-- bind method to the components `this`
}
myValue = 'some value';
addTodo(){
console.log( 'ok, value is:', this.myValue );
}
render() {
return <>
<button onClick={ this.addTodo } > works without arrow function </button>
</>;
}
}
Remark:
I would recommend that you just should forget that you have ever read the misleading recommendation in that blog post, and find better sources of knowledge.
I think closures, the .bind(this)
pattern and optimizing functional components are beyond the scope of this question topic.
If you still want to optimize your functional component, unrelated to that blog post, then I think you should ask a new question.
Performance difference between using arrow functions and partial application in render functions?
In both the cases the returned function is created on every render which affects performance when you have a large application and a lot of such patterns.
The major problem will come when you have nested components as PureComponent
or you implement shouldComponentUpdate
with shallow
comparison of props and when you pass arrow functions as props, the shallow check in PureComponent
fails causing performance issues.
Sample demo
class Child extends React.Component { shouldComponentUpdate(nextProps) { if(this.props.onClick === nextProps.onClick) { console.log('same click'); } else { console.log('different click'); } if(this.props.onChange === nextProps.onChange) { console.log('same change'); } else { console.log('different change'); } return true; } click = () => { this.props.onClick('xyx'); } render() { return <button onClick={this.click}>Click</button> }}class App extends React.Component { constructor(props) { super(props); this.state = { count: 0 } } componentDidMount() { this.timer = setInterval(() => { this.setState(prev => ({count: prev.count+ 1})); }, 1000) } handleClick = (id) => (value) => { console.log(id, value); } componentWillUnmount() { clearInterval(this.timer); } handleChange = (val) => { console.log(val) } render() { return ( <div><Child onClick={this.handleClick(1)} onChange={() => this.handleChange(1)} count={this.state.count}/></div> ) }}
ReactDOM.render(<App />, document.getElementById('app'));
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.6.3/umd/react.production.min.js"></script><script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.6.3/umd/react-dom.production.min.js"></script><div id="app" />
React: Which is recommended arrow or normal function?
There are so many answers around there but people always get confused. I know this because I got confused once a while ago. After some time, I grasped the concepts.
- Bind object/function manually in order to play with state or props
inside the function and to avoid scope-related issues
Not exactly true. You don't need to bind the functions to play with state or props. You bind the function to this
when you lose this
context in the scope. For example in a callback function.
class App extends React.Component {
state = {
name: "foo",
}
aFunction() {
console.log( this.state.name );
}
render() {
return <div>{this.aFunction()}</div>;
}
}
You don't need to bind your function since this
points your class and you don't lose its context. But if you use your function in a callback like a button, you have to bind it:
class App extends React.Component {
state = {
name: "foo",
}
aFunction() {
console.log( this.state.name );
}
render() {
return (
<div>
<button onClick={this.aFunction}>Click</button>
</div>
);
}
}
This does not work since you lose the context. Now, you need to get its context back somehow right? Ok, let's see how we can do this. First, I want to bind it in the button callback.
<button onClick={this.aFunction.bind(this)}>Click</button>
Yeah, this works. But, it will be recreated in every render. So:
- Bind object/function always in constructor but not directly in render
Yes. Do not bind it like I did above, do it in your constructor.
If you do it in constructor then Webpack creates new object/function in bundle.js file only once when your component
renders for the first timeIf you do it directly in render then Webpack will create a new object/function in bundle.js file every time your component renders
and re-render
You are summarizing here what I've tried to explain up to now. But, I suppose Webpack is not the one doing this, your App is.
- If you don’t bind then you can’t access state or props. You have to assign current object to a local variable otherwise this.state or
this.props is undefined
Again, if you use your function inside your class scope, you don't have to bind it. If you use this function outside of your class, like a button callback, you have to bind it. This is not related to state
or props
. This is related to using this
.
Your second option for binding is doing the binding in the constructor by using a regular function and the third one is using an arrow function without binding.
Now, arrow functions.
1.No need to bind an object/function in constructor nor render
Yes.
- You no need to depend on local variable interms of current object i.e., let that = this;
Yes.
- You will not have scope issues and object/function binding takes automatically
Yes.
But my query is that I heard that it’s recommended to use normal
function and bind it in constructor rather than using arrow function
because arrow functions create new object/function in Webpack
bundle.js every time your component renders & re-renders.
Like everybody said, that depends on where you use them.
render() {
return (
<div>
<button onClick={() => this.aFunction()}>Click</button>
</div>
);
}
Here, it will be recreated in every render. But if you don't need to pass any argument to it, you can use it by reference.
render() {
return (
<div>
<button onClick={this.aFunction}>Click</button>
</div>
);
}
This works as the previous one. So, if you see a ()
in your render method, this function recreated in every render. Regular or an arrow one, doesn't matter. If you are invoking it somehow, then you are recreating it. This applies to bind in the render like aFunction.bind(this)
. I see ()
there.
So, use functions by their references to avoid this issue. Now, the big question is what happens when we need some arguments? If you use an arrow function to pass an argument then try to change your logic.
But is it really important as much? Like @Eric Kim said, optimizing is an issue if you really need it. This is a general suggestion since I've heard this from lots of people. But personally, I am trying to avoid using functions if they will be recreated in every render. But again, this is totally personal.
How can you change your logic? You are mapping over an array with an item and creating
a button. In this button, you are using a function that passes item's name to a function.
{
items.map( item =>
<button onClick={() => this.aFunction(item.name)}>Click</button>
)
}
This function will be recreated in every render for each item! So, change your logic, create a separate Item
component and map it. Pass the item
, aFunction
as props. Then with a handler function in this component use your function.
const Item = ( props ) => {
const handleClick = () => props.aFunction( props.item.name );
return (
<button onClick={handleClick}>Click</button>
);
}
Here, you are using an onClick
handler with its reference and it invokes your real function. No function will be recreated in every render. But, as a downside, you need to write a separate component and a little bit more code.
You can apply this logic most of the time. Maybe there will be some examples you can't, who knows. So the decision is yours.
By the way, the Medium post that @widged gave in the comments is a famous discussion about this issue. Are arrow functions really slower than the regular ones? Yes. But how much? Not so much I guess. Also, this is true for transpiled code. In the future when they become native, then they will be the faster ones.
As a personal side note. I was using arrow functions all the time since I like them. But a while ago in a discussion, someone said
When I see an arrow function in the class I think that: 'This function
is being used/called outside of this class'. If I see a regular one I
understand that this function called inside the class.
I really liked this approach and now if I don't need to call my function outside of my class I am using a regular one.
React.js: the most efficient way to pass a parameter to an event handler without bind() in a component
I have explained it in my another post: click event in react component.
Never use inline arrow function if you're worried about its performance. You can still use the public class method and bind the context this
.
handleClick = () => () => {
this.setState({ // this works now
isClicked:true
});
}
You can pass any parameters you like just like this:
handleClick = (param1, param2, param3) => (event) => {
As per devserkan's comment,
This is currying and same as other options. This function is also recreated in every render.
No. It doesn't. See the note from docs:
If this callback is passed as a prop to lower components, those components might do an extra re-rendering. We generally recommend binding in the constructor or using the class fields syntax, to avoid this sort of performance problem.
Also, see the comment from bigga-hd below the certainperformance's answer:
Avoid declaring arrow functions or binding in render for optimal performance. Declare your functions outside of render. No more function allocations on each render.
How do you call this handler?
You can call the method just like this:
onClick={this.handleClick(param1,param2,param3)}
PS: I did not mark this post as duplicate as question scope is significantly different. So, just linked the post to get you dig into more detail.
Related Topics
How to Cancel an Http Fetch() Request
What Is the Meaning of the 'G' Flag in Regular Expressions
Object Property Name as Number
Why Does Firebase Lose Reference Outside the Once() Function
Strip All Non-Numeric Characters from String in JavaScript
How to Find Out What Character Key Is Pressed
Hot and Cold Observables: Are There 'Hot' and 'Cold' Operators
Trying to Fire the Onload Event on Script Tag
Javascript: Filter() for Objects
Es6 Modules: Export Single Class of Static Methods or Multiple Individual Methods
JavaScript Document.Getelementsbyclassname Compatibility with Ie
Async/Await Always Returns Promise