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.

  1. 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:

  1. 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.

  1. 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 time

  2. If 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.

  1. 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.

  1. You no need to depend on local variable interms of current object i.e., let that = this;

Yes.

  1. 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.

Leave a Comment