Search code examples
javascriptreactjsarrow-functionsecmascript-nextclass-fields

Correct use of arrow functions in React


I am using ReactJS with Babel and Webpack and using ES6 as well as the proposed class fields for arrow functions. I understand that arrow functions make things more efficient by not recreating the functions each render similar to how binding in the constructor works. However, I am not 100% sure if I am using them correctly. The following is a simplified section of my code in three different files.

My code:

Main.js

prevItem = () => {
    console.log("Div is clicked")
}

render(){
    return (
         <SecondClass prevItem={this.prevItem} />
    )
}

SecondClass.js

<ThirdClass type="prev" onClick={()=>this.props.prevItem()} />

ThirdClass.js

<div onClick={()=>{this.props.onClick()}}>Previous</div>

Question:

Is my code above using the arrow functions correctly? I noticed that for SecondClass.js I could have also used:

<ThirdClass type="prev" onClick={this.props.prevItem} />

Is there a difference between one method or the other since I used an ES6 arrow function in my original function definition? Or should I be using the arrow syntax all the way through until my last div?


Solution

  • 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