What are the differences between functions and classes in React?

For anyone new to React, you might be wondering why all the tutorials keep changing the pre-generated code from create-react-app over into a class.

The quick answer is that it has to do with states. But before we dig into that, let’s look at the differences between a function and a class in React.

A function in React looks something like this:

function App(){
     //some code here
 
 
     return(
         <div className="App">
             <!-- some html here -->
         </div>
     )
 }

In contrast, a component class in React looks something like this:

import { Component } from 'react'
 
 class App extends Component {
     constructor(){
         super();
     }
     
     render(){
         return(
             <div className="App">
             <!-- some html here -->
             </div>  
         )
     }
 }

When we look at it, a function looks simpler to deal with. However, a function in React is simply just that — a function. Its main and only capabilities are to accept props and return a React element.

Well, this is all before React 16.8 came into the scene.

The newest versions of React let you use the useEffect hook to use lifecycle events in your functional components. Back in the day before 2019, lifecycle events were only available to React.Component, which is something you extend from in your class Component .

It used to be that if you wanted to use states through lifecycle hooks, you’d need to use a React class instead of a function.

This is no longer the case.

So how do you use the useEffect hook?

Let’s take a look at the code sample below.

import React, { useState, useEffect } from 'react';
 
 function App() {
 
     const[name, setName] = useState('Dotted');
     
     useEffect(() =>{
         console.log('change has occured');
     }, [name])
 
   function changeName(){
     setName('Squirrel');
   }
     
     return(
     <div className="App">
         <h1>{name}</h1>
         <button onClick={() => changeName()} > 
         Change my name!
         </button>
     </div>
     )
 
 }

The above function has three parts to it:

[1] The state is represented through const[name, setName]=useState('Dotted')

  • the state takes parameters — the thing that is used to represent the variable (i.e. name) and the setter function (i.e. setName)

[2] useEffect() function, which takes 2 parameters

  • the first parameter deals with what happens when a change has occurred. You can put whatever you want in here like code and functions.
  • the second parameter is the ‘watcher’ parameter that detects when a change has occurred and triggers the code in the first parameter. In our case, it’s when name is changed via setName function.

[3] The returned React component

  • This is what the users see. In the code above, there is a button with an onClick function that lets you write code to execute. In our case, it is an anonymous function that takes no parameters and runs changeName()

In contrast, if we wanted to write the same thing but as a React class, here’s what it’ll look like:

import { Component } from 'react'
 
 class App extends Component{
 
   constructor(){
     super();
 
     this.state = {
       name: 'Dotted'
     }
 
     this.changeName = this.changeName.bind(this)
   }
 
   changeName(){
     this.setState({ name: 'Squirrel' })
   }
 
   render(){
     return(
       <div className="App">
         <h1>{this.state.name}</h1>
         <button onClick={this.changeName} >
           Change my name!
         </button>
       </div>
     )
   }
 
 }

There are three parts to the code above:

[1] The state, as represented through this.state = {name: 'dotted'}

  • the state needs to be declared inside the constructor. The purpose of the constructor is to initialize an object and prepare it for use.

[2] The changeName() function which accesses the setState method in order to change the state of name to Rose.

[3] The returned React component, which must be wrapped inside render() to work.

  • onClick lives here and lets you access changeName() via this. However, this.changeName needs to be manually bound to this . To achieve this, you need to bind and set the function inside the constructor. If you don't do this, you will get uncaught TypeError: Cannot read property 'setState' of undefined from React.

Let’s cut the chase: Classes or Functions in React?

With the release of React 16.8 in early 2019, a major gap between classes and functions has been reduced significantly. The ability to use states in function makes creating React components much more economical for a developer.

So why should you use class components at all?

The main answer to this is to do with the ability to create extensibility. With classes, you can use the extends keyword to create child classes and set up inheritable features. In contrast, a React function component is closed off.

When and where you’d use extends is beyond the scope of this piece and perhaps for another time to write about.

A React component function is easier to deal with, especially if you’re working with atomic design principles. It is much easier to read because it is mostly just plain JavaScript functions. You also end up with less code.