function versus const for React components

Published January 2, 2022

In React, we can write components using the function keyword or the const keyword and an arrow function.

Using const and an arrow function

const MyComponent = () => {
  return(
    <p>My component</p>
  )
}

Using the function keyword

function MyComponent() {
  return (
    <p>My component</p>
  );
}

The first approach creates a function using the JavaScript arrow function syntax and stores it in a constant variable. The second approach with the function keyword creates a plain function that most of us are used to.

Both are functions that will perform the exact same task, which is to return the React component's JSX code for rendering.

Using const and arrow functions has become more popular lately. Many developers find the function keyword syntax more verbose.

Is there a difference between the two approaches or can we always use either approach interchangeably? There is one important difference between the two. That difference is related to hoisting.

Hoisting

Hoisting is something that JavaScript does during its compile phase, just microseconds before code is executed. That code is scanned for function and variable declarations. All functions and variable declarations are added to memory inside a JavaScript data structure. This is so that they can be used even before they are actually declared in the source code.

helloWorld();  
// prints 'Hello World' to the console

function helloWorld(){
  console.log('Hello World');
}

Since function declarations are added to memory during the compile stage, we are able to access the helloWorld() function even before it is declared.

Hoisting with let

Using a let variable before it is declared will result in a ReferenceError. The variable username is in a "Temporal Dead Zone" from the start of the code block until it is actually declared using let username = "Mario".

try {
  username = "Luigi";
  let username = "Mario";
}
catch(err) {
  console.log(err);
  // ReferenceError: Cannot access 'username' before initialization
}

Hoisting with const

Using an uninitialized const variable before it is declared is a syntax errror. The code will throw an error.

try {
  username = "Luigi";
  const username;
}
catch(err) {
  console.log(err);
  // Uncaught SyntaxError: Missing initializer in const declaration
}

If we do initialize the const declaration, like we did with let, we will get the same error as we got with let above.

try {
  username = "Luigi";
  const username = "Mario";
}
catch(err) {
  console.log(err);
  // ReferenceError: Cannot access 'username' before initialization
}

The function, let, and const declarations are all hoisted. However, the let and const declarations remain unitialized. They are only initialized when the variable assignment is evaluated at runtime by the JavaScript engine. This means that we cannot access let and const variables before the JavaScript engine evaluates their values at the place where they were declared. This is what is referred to as a "Temporal Dead Zone." It is a time span between variable creation and variable initialization where variables cannot be accessed.

Hoisting and React components

Let's apply what we learned from the hosting of const variables to React components.

const App = () => (
  <>
    <MyComponent />
    <MyOtherComponent />
  </>
);
export default App;

const MyComponent = () => {}

const MyOtherComponent = () => {}

In this example, the linter will throw an error because MyComponent and MyOtherComponent are used before they are declared.

We can fix the error by moving the component declarations to the top of the file.

const MyComponent = () => {}

const MyOtherComponent = () => {}

const App = () => (
  <>
    <MyComponent />
    <MyOtherComponent />
  </>
);
export default App;

If we want to keep our component declarations at the bottom of a file and then use them before they are declared, we should use the function syntax. This will allow them to be hoisted to the top of the file.

Here is the same example re-written with the function syntax in order to keep component declarations at the bottom of the file and fix the error.

 const App = () => (
  <>
    <MyComponent />
    <MyOtherComponent />
  </>
)

function MyComponent() {}

function MyOtherComponent() {}

Conclusion

React components declared with the function keyword can be called even if their function definition is further down in the code. React components declared with const and arrow functions will still get hoisted, but they cannot be called until after they are defined.