12

Since React Hooks, I have decided to let go of React class components. I'm only dealing with hooks and functional components now.

Simple question:

I understand the difference between using an arrow function instead of a regular function inside of a class body. The arrow function would automatically bind (lexical this) to the instance of my class and I don't have to bind it in the constructor. This is nice.

But since I'm not dealing with classes anymore, I would like to know what is the difference of doing the following inside of a functional component:

function App() {

  // REGULAR FUNCTION
  function handleClick1() {
    console.log('handleClick1 executed...');
  }

  // ARROW FUNCTION
  const handleClick2 = () => {
    console.log('handleClick2 executed...');
  }

  return(
    <React.Fragment>
      <div className={'div1'} onClick={handleClick1}>
        Div 1 - Click me
      </div>
      <div className={'div2'} onClick={handleClick2}>
        Div 2 - Click me
      </div>
    </React.Fragment>
  );
}

QUESTION

Both works fine.

Is there a difference in performance? Should I favor one way instead of the other? They're both recreated on every render, correct?


NOTE ON POSSIBLE DUPLICATES

I really don't think this is a duplicate question. I know there are plenty of questions about the difference between arrows and regulars, but I want to know from the perspective of a React functional component and how React handles with it. I've looked around and didn't find one.


CODE SNIPPET FOR TESTING

function App() {
  
  function handleClick1() {
    console.log('handleClick1 executed...');
  }
  
  const handleClick2 = () => {
    console.log('handleClick2 executed...');
  }
  
  return(
    <React.Fragment>
      <div className={'div1'} onClick={handleClick1}>
        Div 1 - Click me
      </div>
      <div className={'div2'} onClick={handleClick2}>
        Div 2 - Click me
      </div>
    </React.Fragment>
  );
}

ReactDOM.render(<App/>, document.getElementById('root'));
.div1 {
  border: 1px solid blue;
  cursor: pointer;
}

.div2 {
  border: 1px solid blue;
  cursor: pointer;
 }
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.8.3/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.8.3/umd/react-dom.production.min.js"></script>
<div id="root"></div>
Flip
  • 6,233
  • 7
  • 46
  • 75
cbdeveloper
  • 27,898
  • 37
  • 155
  • 336
  • 1
    If you're not using `this` then the difference is completely irrelevant inside the function. The difference outside is that function declarations are hoisted to the top of the scope, assigning an arrow function to a variable (var, const, let) is not. There's a further difference in how var differs from const and let, but that only matters if you reference something before it's assigned. – Jared Smith May 03 '19 at 11:22
  • 1
    Whatever other info you've read about arrow functions vs regular named functions vs anonymous functions declared with variables still applies here. [There is no performance difference](https://stackoverflow.com/a/44031830/8237835) between them. And it's not even possible to detect if a function is an arrow function at runtime so React doesn't and can't handle them differently than regular functions. – Khauri May 03 '19 at 11:24
  • 1
    Per the earlier comment see [this](https://stackoverflow.com/questions/762011/whats-the-difference-between-using-let-and-var) and [this](https://stackoverflow.com/questions/336859/var-functionname-function-vs-function-functionname/338053). – Jared Smith May 03 '19 at 11:26
  • 2
    Oof. I was wrong about not being able to detect arrow functions. https://stackoverflow.com/questions/28222228/javascript-es6-test-for-arrow-function-built-in-function-regular-function but I highly doubt React is doing that anyway. Mostly because of transpilers being a thing. – Khauri May 03 '19 at 11:40
  • See also https://stackoverflow.com/a/55784719/3731501 – Estus Flask May 03 '19 at 12:03

2 Answers2

5

Beside the differences you've already pointed out (lexical scope), arrow functions (and function expressions) are not hoisted, and as such cannot be called before they are defined. See my example. This is in my opinion not a problem, since code that relies on hoisting is much harder to reason about.

React really doesn't care about which one you use (nor can it detect it).

const A = () => {
  const name = getName();
  
  function getName() {
    return 'praffn';
  }
  
  // Will not work
  // const getName = () => 'praffn';
  
  return <p>Hi, {name}</p>;
}

ReactDOM.render(<A/>, document.getElementById('root'));
<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="root"></div>
Phillip
  • 6,033
  • 3
  • 24
  • 34
  • 2
    Personally I haven't found function hoisting to be much of an issue in practice (unlike `var` hoisting) and I think having the `function` keyword there makes the code more readable than it would be with nearly everything starting with `const`. (I suspect Facebook might have similar reasons for using `function` in their examples.) But as Phillip already pointed out, this is a stylistic preference—either will work fine. – Matt Browne May 03 '19 at 11:35
  • 2
    @MattBrowne, I actually prefer using the `function` keyword - to me it is much more readable. I usually only use arrow functions for one-liners and when used in higher order functions. I do however refrain from relying on hoisting when possible. – Phillip May 03 '19 at 11:38
  • @MattBrowne I think that the `function` keyword makes the code more readable too. And I hardly ever use the hoisting "feature". – cbdeveloper May 03 '19 at 11:41
5

Since you are not accessing the this context, both will both behave the same.

To understand more, you can check how babel is transpiring to the ECMA:

 const handleClick2 = () => {
    console.log('handleClick2 executed...');
    this.x=3
 }

will be transpiled as:

"use strict";

var _this = void 0;

var handleClick2 = function handleClick2() {
  console.log('handleClick2 executed...');
  _this.x = 3;
};

Link to babel notepad

ykaragol
  • 6,139
  • 3
  • 29
  • 56
  • 1
    Accessing `this` inside of an arrow function or function declaration will not give any difference since `this` will be equal to `undefined`. This is because `React components are written within ES6 modules, which automatically run in strict mode`. – Ani Naslyan Nov 09 '21 at 17:50