Higher-Order Components (HOC) in React

React

readTime

5 min

Higher-Order Components (HOC) in React

If you're a React developer, you've probably come across the term Higher-Order Component (HOC).

It's an interesting pattern that allows you to share logic between components without modifying their internal code.

In this article, I'll explain what an HOC is, how it works, its common use cases, and how to implement it.

I'll also discuss the pros and cons of using higher-order components in React applications.

What is a Higher-Order Component (HOC)?

Let’s start with the basics. A Higher-Order Component (HOC) is a pattern in React where a function takes a component as an argument and returns a new component that extends the original one with additional functionality.

Simply put, it's a pure function that transforms one component into another.

You can think of it as a decorator that adds new features to a component without modifying its original code. πŸ’‘

Here’s an example of a simple higher-order component:

javascript
const withHOC = (WrappedComponent) => {
  return (props) => {
    return <WrappedComponent {...props} />;
  };
};

In this example, the withHOC function takes WrappedComponent (the original component) as an argument and returns a new component that passes all the props to the original component, without changing its internal logic.

How do Higher-Order Components work?

To understand HOC, it's essential to know how the props system and rendering work in React.

An HOC works as a "wrapper" that you can apply to other components to give them additional functionality.

The key is that an HOC does not modify the original component; instead, it creates a new component that contains both the original logic and new functions.

HOCs are higher-order functions, meaning they work on components in the same way higher-order functions in JavaScript operate on other functions.

Simple HOC Example πŸ› οΈ

Here's an example of an HOC that adds a simple loading message while data is being fetched:

javascript
import { useEffect } from "react";

const withLoading = (WrappedComponent) => {
  return (props) => {
    const [isLoading, setIsLoading] = React.useState(true);

    useEffect(() => {
      const timer = setTimeout(() => {
        setIsLoading(false);
      }, 2000); // Simulated data fetching

      return () => clearTimeout(timer);
    }, []);

    if (isLoading) {
      return <p>Loading data...</p>;
    }

    return <WrappedComponent {...props} />;
  };
};

In this example, withLoading is an HOC that takes a component as an argument and then returns a new component with additional state (isLoading).

Once the component is mounted, data fetching is simulated, and after two seconds, the component renders with the passed-in props.

This allows you to easily add loading functionality to any component without changing its internal code.

Use Cases for Higher-Order Components πŸš€

Higher-order components are particularly useful when you need to share common logic across different components. Here are a few typical use cases:

1. Authorization πŸ”

In React applications, some pages may only be accessible to authenticated users.

You can create an HOC that checks if the user is logged in before rendering the component:

javascript
const withAuth = (WrappedComponent) => {
  return (props) => {
    const isAuthenticated = checkIfAuthenticated(); // Function that checks authentication

    if (!isAuthenticated) {
      return <Redirect to="/login" />;
    }

    return <WrappedComponent {...props} />;
  };
};

2. Activity Logging πŸ“

You can create an HOC that logs user activity every time a component updates:

javascript
import { useEffect } from "react";

const withLogger = (WrappedComponent) => {
  return (props) => {
    useEffect(() => {
      console.log(`Component ${WrappedComponent.name} has been updated`);
    });

    return <WrappedComponent {...props} />;
  };
};

3. Theme Selection 🌈

You can create an HOC that adds appropriate styles depending on the current theme of the application:

javascript
const withTheme = (WrappedComponent) => {
  return (props) => {
    const theme = getTheme(); // Function that retrieves the current theme
    return <WrappedComponent {...props} theme={theme} />;
  };
};

Advantages of Higher-Order Components

Why use HOCs in React?

  • Reusability: HOCs allow you to share logic between components, reducing code duplication.
  • Modularity: By separating logic from components, you can create more modular and scalable code.
  • Flexibility: HOCs can accept additional arguments, making them adaptable to various use cases.

Disadvantages of Higher-Order Components πŸ€”

One potential problem is the so-called "wrapper hell" – when too many HOCs are stacked onto a single component, making it hard to debug and track the flow of props.

This can also negatively impact the readability of the code.

HOCs vs React Hooks πŸ”„

Since the introduction of React Hooks, many HOC use cases can now be replaced with hooks, which are more intuitive and easier to manage.

For example, the state management for loading can be handled using the useState hook instead of an HOC:

javascript
import { useEffect } from "react";
function useLoadingData() {
  const [isLoading, setIsLoading] = React.useState(true);

  useEffect(() => {
    const timer = setTimeout(() => setIsLoading(false), 2000);
    return () => clearTimeout(timer);
  }, []);

  return isLoading;
}

If you're interested, I also have an article on fetching data in React using built-in hooks.

Hooks allow you to share logic without creating new components, which makes them a simpler alternative for many scenarios.

However, HOCs still have their place in React, particularly for more advanced functions like authentication or user activity logging.

Conclusion

Higher-Order Components (HOCs) are a powerful tool for sharing logic between components without modifying their internal code.

They allow you to add additional features, increasing the modularity and flexibility of your code.

However, it's essential to use HOCs with caution to avoid overcomplicating your application.

In simpler cases, it's worth considering React Custom Hooks, which provide a modern approach to sharing logic in functional components.

Try building your own higher-order component and see how it can simplify your workflow!

authorImg

Witek Pruchnicki

I passionately share knowledge about programming and more in various ways.