Published on

Const vs. Function For React Functional Components

Authors
  • avatar
    Name
    Jacob Toftgaard Rasmussen
    Twitter

Const vs Function cover photo For some time now I have been wondering if there is a benefit to using function over const when declaring functional components, and vice versa. So, I decided to do a little research, and I will sum it up for you in this article.

TLDR

It does not really matter whether you use one or the other. The most important technical difference is that functional components defined using function are hoisted whereas those using const are not. However, this has no pragmatic consequence as long as you define your components in separate files and import them at the top of the files where you need them. This is most likely the way that you are structuring your files anyway, which is why it does not really make a difference

The biggest benefit that I found to using the function syntax is when using Visual Studio Code as editor. This is because VSC gives you the option to refactor a function to a new file, but this option is not available if you have used the const syntax.

Additionally, some people have a preference towards one of them because of readability. However, that is subjective and you can decide for yourself what you prefer.

In the end it is the difference in utility from VSC that makes me prefer function over const when declaring functional components in React. Apart from that, I have not found any practical differences between the two.

For the curious, you can find further details below.

A technical difference — Hoisting

JavaScript has a concept called Hoisting which allows for variables and functions to be declared on lines below the lines where they are used. It is a bit complex, and it would require more explanation to fully understand than I want to include here. So, instead I will show you what it means in terms of our components.

The following code gist contains two modified index.tsx files, which are normally the entry point to your React application. The first one is invalid and will cause an error, whereas the second one is valid. The only difference between them is where the Header component is initialized. In the first file it is initialized on line 14 which is below line 9 where it is being used. And in the second file it is initialized on line 7 which is before its use on line 13.

import React from 'react'
import ReactDOM from 'react-dom/client'
import App from './App'

const root = ReactDOM.createRoot(document.getElementById('root') as HTMLElement)

root.render(
  <div>
    <Header/>
    <App />
  </div>,
)

const Header = () => {
  return <>Header</>
}
import React from 'react'
import ReactDOM from 'react-dom/client'
import App from './App'

const root = ReactDOM.createRoot(document.getElementById('root') as HTMLElement)

const Header = () => {
  return <>Header</>
}

root.render(
  <div>
    <Header/>
    <App />
  </div>,
)

This screenshot of a code sandbox shows the error that will occur, when the const function is used before it is initialized. (Don’t mind the red squiggly line on line 2)

Code sandbox showing an invalid use of the const keyword

Let’s now take a look at the same code, just using the function keyword for the Header component instead. Code sandbox showing a valid use of the keyword function

The code sandbox above shows that the code runs correctly when using the function syntax. (The squiggly red line on line 11 occurs because the current linting rules do not approve of using a function before it is defined, however this is only linting.)

This shows that there could be a potential technical benefit to using function instead of const.

But does it really matter in a real world project… Photo by Juan Rumimpunu on Unsplash

I would argue no.

This is because I will almost always define my components in separate files, and then import them into the files where I want to render them. And my import statements are always at the top of my files. Because of this, my const components will always be defined above the lines of code that actually run them.

This means that even in the cases like the following it does not become a problem. Code sandbox showing that defining components with const, is not really a problem even though they are not hoisted

But wait a moment, how does the above example work? Why is there no problem in using InnerComponent inside of App? Even though it is defined below App.

My theory is, that the determining factor is the order of the code at runtime and not at compile/interpretation time. The entry point for rendering the app at runtime is the call to root.render(<App />); on line 8, which happens after the import statement on line 3 in index.tsx. As such, the initialization of InnerComponent is above root.render(<App />); and is therefore already initialized once the App component needs it.

Let’s take a look at a small toy example in pure JavaScript to make it easier to wrap your head around. Working example with call to later defined function after its definition

In the screenshot of the code sandbox above the InnerComponent is defined below the definition of the function expression AppEntry. However, the call to AppEntry happens after InnerComponent has been initialized, and as a result there is no problem at runtime, even though it is a function created using const. (This resembles most of our use cases in React) Example showing how InnerComponent cannot be used before its initialization at runtime

If instead we move the AppEntry call up before InnerComponent, then we see the problem occurring because the const function expression is not being hoisted. (But I don’t think this will ever happen to you, since the entry point of your app is most likely in index.tsx and all other components will be imported above the initial render function)

Lastly, if we use the function keyword instead to declare InnerComponent, then the hoisting kicks in, and it works as seen in the following screenshot. Example showing that the function keyword causes the function to be hoisted

A Visual Studio Code difference

Now that we have gotten the technical difference out of the way, which I suggest is almost non existing, let’s take a look at a utility difference that I have noticed when using VSC.

VSC allows you to refactor functional components out into new separate files if you have declared them using function, but not if you have used const. gif showing refactoring options of function in VSC

Same function just declared using const. gif showing refactoring options of const in VSC

For me, this is actually the most important benefit to using function instead of const. Because it removes a tedious step of creating new files and writing boilerplate code.

When this has been said however, the refactoring options (as seen in the second gif) allow you to convert the const functional expression to a named function, so you can quickly make the switch, especially if you use the keyboard shortcuts.

Subjective benefits (readability)

A last thing to consider is the readability of the syntax. This is of course a subjective matter, and some people prefer the function syntax whereas others prefer the const syntax.

One argument that I do like is that the function syntax resembles function declarations of other programming languages the most, and it is therefore easier for non JavaScript developers to understand that syntax compared to the fat arrow syntax.

Final words

My conclusion to this question is that it does not really matter which syntax you use. Just use the one that you prefer. Maybe like me, the difference in VSC could be the determining factor for you. Maybe it is the readability that does it for you?

If you have any additions or knowledge about this (maybe I missed something important) then please reach out and share it.

Thanks for reading and have a great day!