Greetings on my blog about web programming!

Higher-Order Components in the modern world.

In this article I want to write about what a Higher-Order Component (HOC) is and most importantly in what situations it can be useful.

In simple words, a higher order component is a universal wrapper for a component that gives it additional functionality. HOC is a pure function, it does not change global variables, depends only on incoming data and does not modify the passed component.

Benefits of using HOC:

  • Reusability of logic. By combining repetitive functionality in a HOC, we avoid code duplication.
  • HOC can take over realization of such tasks as: authentication checking, logging, error handling, etc.

Using the HOC of this pattern in React. This pattern can be used both in class and functional components.

Let’s look at a simple example of HOC. Often in an application we need to restrict access to certain pages depending on whether the user is authorized or not. HOC is usually called with the prefix with, so in our case let’s call it withAuth

import { useSelector } from 'react-redux';
import { Navigate } from 'react-router-dom';

const withAuth = (WrappedComponent) => {
  const isAuth = useSelector(isAuthSelector);

  const WithAuth = () => {
    return isAuth ? <WrappedComponent /> : <Navigate to="/" />;
  };

  return WithAuth;
};

As we can see our HOC accepts only the wrapper component without modifying it in any way. It takes a variable isAuth from the Redux store and depending on the value either returns wrapped componend or redirects to the login page.

Now use this HOC for a component, such as Dashboard.

const Dashboard = () => {
  return <div>Dashboard content</div>;
};

export default withAuth(Dashboard);

After that, we can use this component without worrying about it being seen by an unauthorized user.

const App = () => {
  return <Dashboard />;
};

Alternatives for HOC in modern React app

However, according to the official React documentation:

Higher-order components are not commonly used in modern React code.

React docs

One reason: the emergence of hooks in React.
Now we can put repetitive logic into a custom hook. One advantage of this approach is better code readability and obviousness of the returned data.

One blog described the problem of HOC. When you combine them, it is not obvious which props will get into the wrapped component.

App     withFetch   withError   withLoading   DataTable

        data->      data->      data->        data
url->   error->     error
        isLoading-> isLoading-> isLoading

You can read about it here.

And when we create a custom hook for a component, it becomes obvious what it takes and what it returns.
Let’s rewrite our HOC to HOOK

const useAuth = () => {
  const isAuth = useSelector(isAuthSelector);

  return {
    isAuth,
  };
};

Of course, this is too simple logic to separate it into a separate component, but in practice the checks can be much more complex and return more values.
Now we can use this hook in a component.

const Dashboard = () => {
  const {isAuth} = useAuth();

  if (!isAuth) return <Navigate to="/" />
  return <div>Dashboard content</div>;
};

export default Dashboard;

Although we will have to repeat this check in some components, the upside is the obviousness of the custom hook’s return values and simplified testing.
Often HOC helps to avoid code duplication. But sometimes it is not the best solution and it is preferable to put repetitive logic into custom hooks

Posted by romanCh in Web Development, 0 comments