Class Components vs Functional Components in React

Components are regular JavaScript functions that return renderable results. These components can be defined by creating a class with a render method. React will call that method to evaluate what should be rendered to the screen.

Class components are an alternative way of building components in React; they exist because they were needed in the past. This is before React 16.8, where scenarios and use cases needed them, specifically when dealing with state and side effects.

React 16.8 introduced “React Hooks” for Functional components and brought features which were previously reserved for class components to Functional components. Class components cannot use hooks.

How to Transform a Functional Component into a Class Component

First, we need to add a class and curly braces: inside these, we can start adding methods--for example, the constructor and render methods. We can add as many methods as we want and name them however, we want, but the render method is equivalent to the return statement in a functional component.

To make class components work in general, we need to import components from React and then extend the class from component. This class is defined by React. With this, our class will inherit from the React class component which adds important functionalities and properties. It can be accessed with the ‘this’ keyword containing all the props data received for. With this, we have the equivalent of a functional component.

           Functional Component                                                                                                 Class Component

2       

 

 

 

Managing state works differently in class components

First, we initialize and define the state using the constuctor(); this is automatically called whenever the class is instantiated. In the constuctor(), we initialize the state accessing this state and sett it equal to an object. With class components, the state is always an object and all the state’s licenses and pieces needed in a component are grouped.

To change the state, you must call the method this.setState(), taking an object that contains the new state we want to set without overriding the old state. Instead, React merges the object with the existing state. Another difference between those components is that when we use useState() to update the state, we override the old state.

To use the state, we go to the render method, accessing the state using this.state.name. To call a method we created in our class, we need to use the ‘this’ keyword, but it’s also necessary to add.bind(this) to make sure that the ‘this’ keyword refers to the surrounding class.

It’s important to remember that when we add a constuctor() and we extend from another class, we are required to call super() which calls the constructor of the super class.

4

Side Effect

Class components have a life cycle to handle the side effect. This cycle has different methods you can add to Class components to run code at different points in the life cycle. The most important and common methods are:

  • componentDidMount(): This ibuilt-in method can be used as soon as you extend the built-in component. React will call it when the component is mounted, meaning it was evaluated and rendered to the DOM. This is equal to using useEffect with empty dependencies in a Functional component, just like this:

  • componentDidUpdate(): This is called when a component has been updated.It is the equivalent of useEffect with dependencies.Whenever the dependencies change, the useEffect function re-executes and re-evaluates the dependencies.

                                           

  • componentWillUnmount(): This is called right before the component is removed from the DOM.The equivalent is the clean-up function from useEffect(), which is called right before the effect function is executed again and when the component is about to be removed from the DOM.

                         

Here is an example of how to transform useEffect with dependencies using componentDidUpdate(). As you can see, it’s leaner using useEffect(). With componentDidUpdate(), we are required to add an if statement to check if the state has changed because without that, we would be creating an infinite loop.

Context

We can still define context as we do with Functional components with thecreate context, initializing some value, and then providing it using the Provider component. There is no equivalent for the useContext() hook we use in Functional components. With useContext() we can listen to multiple contexts in one of the same components by calling the hook multiple times and pointing at different contexts.

However, with Class components this is not possible, because here, we can only connect a Class component to one context. We do that by adding a static property, adding the static keyword, and adding the property contextType after that. Then, we assign a value of nameContext, (name: should be your component’s name)

 

With this, you are telling React that this component should have access to the component’s context, but we can only set the static context type property once. So, if there are two or more contexts that should be connected to the same component, this won’t be an option, and you’ll have to find another option like wrapping it in another component. With that, you can access the context with this.context.name.

11

Advantages of Using Functional Components Over Class Components

As we can see, Functional components are leaner and more flexible. It’s easier to work with state because we have React hooks that help handle state and side effects.

When and Why Class Components are Better

If you’re building error boundaries, then you should work with Class components. The Error Boundary component is a regular Class component that implements the componentDidCatch lifecycle method. This method cannot be added to Functional components and there aren’t any equivalents for this method, so every time you want to build an Error Boundary, it needs to be in a Class component.

The componentDidCatch lifecycle method will be triggered whenever one of the child components throws an error or generates one. These error boundaries help us to ensure our entire application will not crash if something goes wrong. Instead, we can catch those errors and then handle them, just like a try-catch in JavaScript does.

 

Conclusion

Class components were used before React 16.8. They exist because they are necessary. Nowadays, most projects done with React use Functional components as hooks have made everything easier, and the code is leaner and more flexible. Yet, there are cases where we need to use Class components-- for example when we’re required to build an Error Boundary, or the team we joined has a project that has not migrated to React 16.8.

 

Sources:

 

 

Acknowledgement

This piece was written by Ana Luisa Martínez, Finance Team MX.


About Encora

Fast-growing tech companies partner with Encora to outsource product development and drive growth. Contact us to learn more about our software engineering capabilities.

 

Share this post

Table of Contents