Article image React Hooks: An Introduction

14. React Hooks: An Introduction

Page 44 | Listen in audio

React Hooks have revolutionized the way developers build components in React by allowing them to use state and other React features without writing a class. Introduced in React 16.8, Hooks provide a more direct API to the React concepts you already know, such as state, lifecycle, and context.

Before diving into Hooks, it’s essential to understand the problems they solve. Traditionally, React components were either functional components or class components. Functional components were stateless and purely presentational, while class components were stateful and had lifecycle methods. This divide created complexity, especially as the application grew. Class components often led to tangled logic and confusing lifecycle methods, making code harder to maintain and understand.

Hooks address these issues by allowing functional components to become stateful and side-effectful. This means you can use state and lifecycle features without converting your functional components into classes. There are several built-in Hooks in React, each serving a specific purpose. Let’s explore some of the most commonly used ones.

useState

The useState Hook allows you to add state to your functional components. It returns an array containing the current state and a function to update it. Here’s a simple example:

import React, { useState } from 'react';

function Counter() {
  const [count, setCount] = useState(0);

  return (
    <div>
      <p>You clicked {count} times</p>
      <button onClick={() => setCount(count + 1)}>
        Click me
      </button>
    </div>
  );
}

In this example, useState initializes the count variable to 0. The setCount function updates the state whenever the button is clicked, causing the component to re-render with the new count value.

useEffect

The useEffect Hook lets you perform side effects in your components. It serves a similar purpose to lifecycle methods in class components, like componentDidMount, componentDidUpdate, and componentWillUnmount. Here’s how it works:

import React, { useState, useEffect } from 'react';

function Example() {
  const [count, setCount] = useState(0);

  useEffect(() => {
    document.title = `You clicked ${count} times`;

    return () => {
      // Cleanup code here if needed
    };
  }, [count]);

  return (
    <div>
      <p>You clicked {count} times</p>
      <button onClick={() => setCount(count + 1)}>
        Click me
      </button>
    </div>
  );
}

In this example, the useEffect Hook updates the document title every time the count changes. The second argument to useEffect is an array of dependencies. If any value in this array changes, the effect runs again. If you pass an empty array, the effect only runs once, similar to componentDidMount.

useContext

The useContext Hook provides a way to consume context values in functional components. It eliminates the need for Context.Consumer and allows you to subscribe to React context directly. Here’s an example:

import React, { useContext } from 'react';

const ThemeContext = React.createContext('light');

function ThemedButton() {
  const theme = useContext(ThemeContext);

  return <button className={theme}>I am styled by theme context!</button>;
}

function App() {
  return (
    <ThemeContext.Provider value="dark">
      <ThemedButton />
    </ThemeContext.Provider>
  );
}

In this example, ThemedButton consumes the theme value from ThemeContext using useContext. The theme value is provided by ThemeContext.Provider in the App component.

useReducer

The useReducer Hook is an alternative to useState for managing complex state logic. It’s similar to Redux but built into React. Here’s a simple example:

import React, { useReducer } from 'react';

function reducer(state, action) {
  switch (action.type) {
    case 'increment':
      return { count: state.count + 1 };
    case 'decrement':
      return { count: state.count - 1 };
    default:
      throw new Error();
  }
}

function Counter() {
  const [state, dispatch] = useReducer(reducer, { count: 0 });

  return (
    <div>
      <p>Count: {state.count}</p>
      <button onClick={() => dispatch({ type: 'increment' })}>+</button>
      <button onClick={() => dispatch({ type: 'decrement' })}>-</button>
    </div>
  );
}

In this example, useReducer manages the state of a counter. The reducer function specifies how the state should change in response to actions, which are dispatched using the dispatch function.

Custom Hooks

Custom Hooks allow you to extract component logic into reusable functions. They enable you to share logic across components in a clean and efficient way. Here’s an example of a custom Hook:

import { useState, useEffect } from 'react';

function useWindowWidth() {
  const [width, setWidth] = useState(window.innerWidth);

  useEffect(() => {
    const handleResize = () => setWidth(window.innerWidth);
    window.addEventListener('resize', handleResize);

    return () => {
      window.removeEventListener('resize', handleResize);
    };
  }, []);

  return width;
}

function Component() {
  const width = useWindowWidth();

  return <p>Window width is {width}</p>;
}

In this example, useWindowWidth is a custom Hook that listens for window resize events and returns the current window width. The Component uses this Hook to display the window width.

Rules of Hooks

When using Hooks, there are two primary rules to follow:

  1. Only call Hooks at the top level. Do not call Hooks inside loops, conditions, or nested functions. This ensures that Hooks are called in the same order on every render.
  2. Only call Hooks from React function components or custom Hooks. This ensures that all stateful logic is clearly defined and reusable.

These rules are enforced by the eslint-plugin-react-hooks ESLint plugin, which helps you identify violations in your code.

Conclusion

React Hooks have significantly simplified the way we manage state and side effects in React applications. They provide a more functional approach to building components, making code easier to reason about and maintain. By understanding and utilizing Hooks such as useState, useEffect, useContext, and useReducer, you can create powerful, reusable, and clean React components. Additionally, custom Hooks allow you to encapsulate logic and share it across your application, further enhancing code reusability and organization.

As you continue to explore React, you’ll find that Hooks offer a flexible and efficient way to manage component logic, ultimately leading to more scalable and maintainable applications.

Now answer the exercise about the content:

What is one of the primary benefits of React Hooks introduced in React 16.8?

You are right! Congratulations, now go to the next page

You missed! Try again.

Article image React Hooks: An Introduction: Understanding the Motivation Behind React Hooks

Next page of the Free Ebook:

45React Hooks: An Introduction: Understanding the Motivation Behind React Hooks

7 minutes

Earn your Certificate for this Course for Free! by downloading the Cursa app and reading the ebook there. Available on Google Play or App Store!

Get it on Google Play Get it on App Store

+ 6.5 million
students

Free and Valid
Certificate with QR Code

48 thousand free
exercises

4.8/5 rating in
app stores

Free courses in
video, audio and text