From class components to React Hooks (2024)

Starting with version 16.8, React provides a way to use component and global state without the need for class components. This does not mean that Hooks are a replacement for class components, though. There are some benefits of using class components, which I will describe later in this tutorial.

First, I will lead you through handling state in both Hooks and class components, explain what custom Hooks are, and guide you through writing tests for the Hooks. Lastly, you will learn how to automate your tests using continuous integration (CI) with CircleCI.

Prerequisites

To follow along with this tutorial you will need:

Our tutorials are platform-agnostic, but use CircleCI as an example. If you don’t have a CircleCI account, sign up for a free one here.

Hooks vs class-based components

Class components are basically JavaScript Object Oriented classes with functions you can use to render React components. The advantage of using classes in React is that they contain lifecycle methods that identify when state changes and update the global state or the component state using the keyword this.state. In contrast, Hooks are used in React functional components and enable you to have components state and other React features in functional components without the need for classes. React provides a way to Hook into the global state without the class lifecycle methods for updating the global and local state of your applications.

In this section of the tutorial, you will make a counter component that uses both React Hooks and a class to increment and decrement count. Then I will show you how to initialize and update state in both.

Your first step is to clone the repository you will be working with.

Cloning the repository

On a terminal in your working directory, run these commands:

git clone https://github.com/CIRCLECI-GWP/react-class-components-to-hooks.git # Clone repositorycd react-class-components-to-hooks # Change directory to the cloned repository

After you have cloned the repository, install the dependencies and start the application. Run this command:

npm install # Install dependenciesnpm start # Start the application

Once the start command has been run, the application should begin executing on the browser.

From class components to React Hooks (1)

This is a simple React class component that is created by this snippet:

// src/class.jsimport React from "react";class CounterClass extends React.Component { constructor(props) { super(props); this.state = { count: 0 }; } increment = () => { this.setState({ count: this.state.count + 1, }); }; decrement = () => { this.setState({ count: Math.max(this.state.count - 1), }); }; render() { return ( <div className="counter"> <h1>COUNTER</h1> <div className="buttons"> <button onClick={this.increment}>Increment</button> <button onClick={this.decrement}>Decrement</button> </div> <p>{this.state.count}</p> </div> ); }}export default CounterClass;

The constructor method of this snippet sets state to this.state and initializes the count with 0. It then defines functions that are called when the buttons are clicked. These functions update the state using the setState() method. This is the class component implementation of updating the counter application with classes. Next, review how the same is implemented using functional components and Hooks. The src/hooks.js in the cloned repository contains the Hook implementation:

// src/hooks.jsimport { useState } from "react";export default function CounterHooks() { const [value, setValue] = useState(0); const handleIncrement = () => { setValue(value + 1); }; const handleDecrement = () => { setValue(value - 1); }; return ( <div className="counter"> <h1>COUNTER</h1> <div className="buttons"> <button data-testid="increment" onClick={handleIncrement}> Increment </button> <button data-testid="decrement" onClick={handleDecrement}> Decrement </button> </div> <p data-testid="count">{value}</p> </div> );}

Instead of using the this.state as in the previous snippet, you can use the useState() Hook to initialize the state. The useState Hook also has the ability to share state with other components in the application, just like a class component using this.state.

These code snippets demonstrate the improved readability of the code. Not only has the complexity been removed, but you also made the functional component do only one thing - render the counter application. Now that you know what React Hooks are, why not explore the most common Hooks in React and how they are used?

useState vs useEffect Hooks

There are different Hooks you can use to perform operations in React. One of them is the useEffect() Hook. This Hook helps you handle things that are outside the realm of React such as API calls, asynchronous events, and other side effects. The structure of a simple useEffect Hook is shown in this snippet:

useEffect(() => { //Your code here}, []);

The first argument expected by the useEffect Hook, is a callback function where you write the code to be executed. The second is an array [] called a dependency array. If the array is omitted, the callback function will run every time the code changes. If the array is empty, the callback function will run once. If there is a value provided, the callback function will run each time the value changes.

Note: A dependency array is an array that takes dependencies or variables and if the value changes, the callback function runs again.

Next, try using a useEffect() Hook in simple logic to log the value of count to the Chrome browser console. In this case, you want to return the value of the count, so you would add the value to the dependency array as shown in this snippet:

useEffect(() => { console.log(value);}, [value]);

When the component loads and the useEffect Hook is called, the console logs the value of the count to the Chrome browser console. Every time the value of the count changes, the console logs the new value of the count.

The useState() Hook, in contrast, is a Hook used to initialize the state of the application. It takes a value as an argument and returns an array of two values. The first value is the current state and the second value is a function you can use to update the state.

Using React Hooks such as useState() and the useEffect(), you can eliminate the use of lifecycle methods like componentDidMount() and componentDidUpdate(). Instead, you can use the Hook to handle state logic.

Note: Lifecycle methods are built into React. They are used to perform operations when a certain action takes place, such as rendering, mounting, updating and unmounting. They are used in class-based components only.

Having explored some of the Hooks, you can move on to explore some of the advantages and disadvantages of using Hooks.

Advantages of Hooks

  • Hooks don’t need the this to bind the functions for the click events, and also access values in the component or global states.
  • Hooks make code cleaner and easy to read and test.
  • Hooks offer more flexibility and they can be reused, especially custom ones in multiple components.
  • With Hooks, you do not need to use lifecycle methods. Side effects can be handled by a single function.

Disadvantages of Hooks

  • It can be a challenge to get started with Hooks, especially for a new developer.
  • Every time the state changes, the component re-renders unless you use other Hooks to prevent this.

Creating custom Hooks

In the previous section, I described the advantages and disadvantages of using Hooks. In this section, I will lead you through creating a custom Hook that can be used anywhere in the counter application. Add this code snippet in the src/components/useCounter.js file:

// src/components/useCounter.jsimport { useState, useEffect } from "react";export function useCounter() { const [value, setValue] = useState(0); const [isEven, setIsEven] = useState(false); useEffect(() => { if (value % 2 === 0) { setIsEven(true); } else { setIsEven(false); } }, [value]); const handleIncrement = () => { setValue(value + 1); }; const handleDecrement = () => { setValue(value - 1); }; return [value, isEven, handleIncrement, handleDecrement];}

This code snippet adds a new state value, isEven, that checks whether the value is even or not. The snippet goes on to check the count value and determine if that is even or odd. It sets isEven to true or false depending on the value.

The callback function inside the useEffect Hook uses an if - else statement to set the value of isEven. It also use a value in the dependency array to ensure that every time count changes, either as a decrement or an increment, the function will run.

The useCounter Hook returns the state values and the increment and decrement functions so that you can access them in the Hooks component.

Now that you have the custom Hook, you can use it to set and update state in the custom-hook.js file:

// src/components/custom-hook.jsimport { useCounter } from "./useCounter";export default function CounterHooks() { const [value, isEven, handleIncrement, handleDecrement] = useCounter(); return ( <div className="counter"> <h1>COUNTER</h1> <div className="buttons"> <button data-testid="increment" onClick={handleIncrement}> Increment </button> <button data-testid="decrement" onClick={handleDecrement}> Decrement </button> </div> <p data-testid="count">{value}</p> <div className={isEven ? "even" : "odd"}>{isEven ? "Even" : "Odd"}</div> </div> );}

This code snippet uses the useCounter() Hook to set state values and also access the increment and decrement functions. It uses those functions to update the state. The isEven state value shows when the counter is even or odd depending on the counter digit displayed on the application.

From class components to React Hooks (2)

Now that you have had some fun with Hooks, it is time to learn how to test them.

Testing Hooks

In this section, I will describe how to write tests for the Hook component. You will be using Jest and react-testing-library, both of which were installed when you set up the cloned application.

Start by testing whether the buttons work. Add this code snippet to the App.test.js file:

// src/App.test.jsimport { render, screen, fireEvent } from "@testing-library/react";import App from "./App";describe("Counter component test suite", () => { test("displays the heading", () => { render(<App />); expect(screen.getByRole("heading").textContent).toBe("COUNTER"); }); test("increment button works", () => { render(<App />); const count = screen.getByTestId("count"); const incrementBtn = screen.getByTestId("increment"); expect(count.textContent).toBe("0"); fireEvent.click(incrementBtn); expect(count.textContent).toBe("1"); }); test("decrement button works", () => { render(<App />); const count = screen.getByTestId("count"); const decrementBtn = screen.getByTestId("decrement"); expect(count.textContent).toBe("0"); fireEvent.click(decrementBtn); expect(count.textContent).toBe("-1"); });});

This snippet “clicks” the increment and decrement buttons to check whether the count value is incremented or decremented. That is asserted against the count value. Run the tests by running npm test in the terminal.

PASS src/App.test.js (5.799 s) Counter component test suite √ displays the heading (432 ms) √ increment button works (77 ms) √ decrement button works (48 ms)Test Suites: 1 passed, 1 totalTests: 3 passed, 3 totalSnapshots: 0 totalTime: 12.097 sRan all test suites related to changed files.

In this case, the tests passed. Hurrah! The snippet shows that the react-testing-library simulates the click events from users on the application, and verifies whether the DOM state of the tests changes to what is expected in these assertions. You can now go the next section and learn how to integrate your tests with a continuous integration pipeline. For this case we will use CircleCI.

Integrating CircleCI

CircleCI is a platform that helps software teams build, test, and deploy automatically through the principle of continuous integration and continuous deployment (CI/CD).

In the root folder of your project, create a .circleci directory and add a config.yml file to it. Add this code snippet to the configuration file:

# .circleci/config.ymlversion: 2.1jobs: build: working_directory: ~/repo docker: - image: cimg/node:21.4.0 steps: - checkout - restore_cache: key: dependency-cache-{{ checksum "package-lock.json" }} - run: name: install dependencies command: npm install - save_cache: key: dependency-cache-{{ checksum "package-lock.json" }} paths: - ./node_modules - run: name: Hooks component tests command: npm test - store_artifacts: path: ~/repo/class-components-to-react-hooks

Commit and push the changes to the repository. Then go to the CircleCI dashboard.

Open the Projects page, which lists all the GitHub repositories associated with your GitHub username or organization. For this tutorial, click react-class-components-to-hooks. Select Set Up Project.

From class components to React Hooks (3)

Select the option to use an existing configuration in the branch main.

From class components to React Hooks (4)

On the CircleCI dashboard expand the build workflow details to verify that all the steps were a success.

From class components to React Hooks (5)

Expand the Hooks component tests build step to verify that the Hooks tests were run successfully.

From class components to React Hooks (6)

Now when you make a change to your application, CircleCI will automatically run these tests.

Conclusion

In this tutorial, you have learned about React Hooks and their role in relation to class-based components. I described the pros and the cons of using Hooks, and how to use different types of Hooks to get the same results you can with class-based components. You were able to use your knowledge about Hooks to write a custom Hook component. You used the custom Hook in the counter application and also wrote tests for it, which you automated in a CI pipeline.

I enjoyed creating this tutorial for you, and I hope you found it valuable. Until the next one, keep learning and keep building!

Waweru Mwaura is a software engineer and a life-long learner who specializes in quality engineering. He is an author at Packt and enjoys reading about engineering, finance, and technology. You can read more about him on his web profile.

Read more posts by Waweru Mwaura

From class components to React Hooks (2024)

FAQs

Can you use hooks with class components? ›

Hooks only work in function components, so if you want to use hooks, you cannot use class components. Aside from error boundaries, a function component with hooks can accomplish everything class components can with more readable and succinct code.

How to convert class component into functional component in React? ›

By using useState, useEffect, and useReducer, you can effectively convert state and lifecycle methods from class components to functional components, resulting in cleaner and more maintainable code.

Why are hooks better than class components? ›

Hooks make code cleaner and easy to read and test. Hooks offer more flexibility and they can be reused, especially custom ones in multiple components. With Hooks, you do not need to use lifecycle methods. Side effects can be handled by a single function.

Are React class components going away? ›

Class components are still supported by React, but we don't recommend using them in new code. componentDidUpdate(prevProps, prevState, snapshot?) forceUpdate(callback?) setState(nextState, callback?)

Why can't hooks be used in class components? ›

Hooks are designed to work with functional components or custom hooks only — because they use the call stack of the functional components to manage the state and lifecycle of the component. Class components do not have this call stack, so you cannot use Hooks directly in them.

Do I need Redux with hooks? ›

While there is no need to race off and convert all your existing code, our recommendation for new code is to generally prefer function components and Hooks over using class-based components and higher-order components. Using the Redux Hooks aligns with this recommendation and provides other key benefits over connect .

Why React moved from class component to functional component? ›

In the rapidly evolving world of React development, the shift from class components to functional components, empowered by Hooks, has been a significant trend. This transformation not only simplifies the syntax and makes components more reusable but also aligns with React's modern, functional programming approach.

How to pass data from class component to functional component? ›

My class component which has the data and adding it to the <PointsLayer component: import React, {Component} from 'react'; export class EventsMap extends Component { constructor(props) { super(props); } render() { const data = this. props.

Can I call a class component in a functional component? ›

Yes, we can call a class component in a functional component in React. This is achieved by using the React Hooks API, specifically the useState and useEffect hooks. There is also difference between functional components vs class components, you should know.

Do I need to rewrite all my class components with hooks? ›

Do I need to rewrite all my class components? No. There are no plans to remove classes from React — we all need to keep shipping products and can't afford rewrites. We recommend trying Hooks in new code.

Why are hooks so powerful? ›

Hooks are thrown with a bent arm and can target an opponent's head or body, making them difficult to defend against. The power generated from the rotational movement of the hips can result in devastating punches that can sway the momentum of a fight.

Why use hooks instead of functions? ›

With stateful logic reuse in React, custom hooks are recommended because helper functions work best for stateless, general-purpose jobs. It is possible to enhance your codebase's modularity and reusability by making the best judgement on when to use both.

Why shouldn't we use class components in React? ›

Class Components in React are like the older, more formal way of building things. They involve more code and can be a bit complex compared to the newer, simpler functional components. Think of them as the traditional way of doing things in React.

What is replacing React? ›

Lit. Lit is a lightweight alternative to React for building web components. Unlike React, it doesn't provide a complete framework but provides tools for building great UI. Lit offers alternatives to React components that are modular and easily maintainable, with efficient DOM manipulation.

Is React being deprecated? ›

In 2023, the Create React App tool was deprecated, which means that it was no longer being maintained. Create React App has been the go-to way to make a new React project, but it's been dethroned by a number of different alternatives.

Can hooks be used in functional components? ›

React effect Hooks are used in functional components to execute side effects. Side effects are things like data fetching, subscription setup and DOM updates that happen outside of a component's render cycle. The two main effect hooks are: useEffect() : This allows you to apply side effects to function components.

How to use useHistory hook in class component? ›

To use the useHistory hook, you first need to import it from the react-router-dom package: import { useHistory } from 'react-router-dom'; 3. Once you have imported the useHistory hook, you can use it in any functional component in your application.

Can I use useState in class component? ›

ONLY call useState() hooks inside a functional component: Hooks are created for functional components and should only be used in functional components. They don't work in class components.

How do I call a hook in a component? ›

Hooks should only be called inside of components or Hooks. Never pass it around as a regular value. Hooks allow you to augment a component with React features. They should always be called as a function, and never passed around as a regular value.

Top Articles
Financial Statement Analysis: What is it & how it works in?
Zeus & family -               Keith Johnson Jr. - Google Arts & Culture
Average Jonas Wife
Patreon, reimagined — a better future for creators and fans
Terrorist Usually Avoid Tourist Locations
Free VIN Decoder Online | Decode any VIN
Toyota gebraucht kaufen in tacoma_ - AutoScout24
Wal-Mart 140 Supercenter Products
Boat Jumping Female Otezla Commercial Actress
Ktbs Payroll Login
Craigslist Jobs Phoenix
Builders Best Do It Center
Insidekp.kp.org Hrconnect
Sivir Urf Runes
Buff Cookie Only Fans
Price Of Gas At Sam's
Patrick Bateman Notebook
Find Such That The Following Matrix Is Singular.
Obsidian Guard's Cutlass
Roof Top Snipers Unblocked
Walgreens San Pedro And Hildebrand
Kylie And Stassie Kissing: A Deep Dive Into Their Friendship And Moments
Vanessawest.tripod.com Bundy
C&T Wok Menu - Morrisville, NC Restaurant
Divina Rapsing
Dmv In Anoka
Pacman Video Guatemala
Craigslist Northern Minnesota
Gunsmoke Tv Series Wiki
Hwy 57 Nursery Michie Tn
Franklin Villafuerte Osorio
Restaurants Near Calvary Cemetery
Ucm Black Board
Shaman's Path Puzzle
One Credit Songs On Touchtunes 2022
Covalen hiring Ai Annotator - Dutch , Finnish, Japanese , Polish , Swedish in Dublin, County Dublin, Ireland | LinkedIn
Boggle BrainBusters: Find 7 States | BOOMER Magazine
Frank 26 Forum
Hebrew Bible: Torah, Prophets and Writings | My Jewish Learning
ENDOCRINOLOGY-PSR in Lewes, DE for Beebe Healthcare
Pepsi Collaboration
2020 Can-Am DS 90 X Vs 2020 Honda TRX90X: By the Numbers
Danielle Ranslow Obituary
Nid Lcms
Centimeters to Feet conversion: cm to ft calculator
Craigslist Pet Phoenix
Motorcycles for Sale on Craigslist: The Ultimate Guide - First Republic Craigslist
Guy Ritchie's The Covenant Showtimes Near Look Cinemas Redlands
Diamond Spikes Worth Aj
Ciara Rose Scalia-Hirschman
Southwind Village, Southend Village, Southwood Village, Supervision Of Alcohol Sales In Church And Village Halls
Latest Posts
Article information

Author: Nathanial Hackett

Last Updated:

Views: 6313

Rating: 4.1 / 5 (72 voted)

Reviews: 95% of readers found this page helpful

Author information

Name: Nathanial Hackett

Birthday: 1997-10-09

Address: Apt. 935 264 Abshire Canyon, South Nerissachester, NM 01800

Phone: +9752624861224

Job: Forward Technology Assistant

Hobby: Listening to music, Shopping, Vacation, Baton twirling, Flower arranging, Blacksmithing, Do it yourself

Introduction: My name is Nathanial Hackett, I am a lovely, curious, smiling, lively, thoughtful, courageous, lively person who loves writing and wants to share my knowledge and understanding with you.