The Road to Next — your interactive course for Next.js with React

React Router: Redirect with Higher-Order Component

Robin Wieruch

When using React Router in React, one can use the Navigate component to navigate a user away from a page in case of a certain condition. For example, the following example does not render a list if there is no data, but redirects a user to the home page instead:

javascript
import { Navigate } from 'react-router-dom';

const List = ({ data }) => {
  if (!data.length) {
    return <Navigate replace to='/home' />;
  }

  return (
    <ul>
      {data.map((item) => {
        return <li key={item}>{item}</li>;
      })}
    </ul>
  );
};

export default List;

In this case the redirect is well placed. However, if there is much logic happening before of the conditional, e.g. by using React Hooks (because they cannot be after a conditional rendering except with this little trick), then the logic has to execute even though there may be a redirect.

javascript
import { Navigate } from 'react-router-dom';

const List = ({ data }) => {
  // lots of hooks here
  // which is bad, because they execute
  // even though there may be a redirect
  // and all the hooks logic may not be used after all

  if (!data.length) {
    return <Navigate replace to='/home' />;
  }

  return (
    <ul>
      {data.map((item) => {
        return <li key={item}>{item}</li>;
      })}
    </ul>
  );
};

export default List;

Therefore, you can use a higher-order component (HOC) for the redirect, because when wrapping the component into a HOC, the logic of the HOC would occur before the hooks from the wrapped component:

javascript
import { withRedirectIfBlank } from './withRedirect'

const List = ({ data }) => {
  // lots of hooks here

  return (
    <ul>
      {data.map((item) => {
        return <li key={item}>{item}</li>;
      })}
    </ul>
  );
};

export default withRedirectIfBlank({
  redirectCondition: (props) => !props.data.length,
  redirectTo: '/home',
})(List);

The HOC implementation could look like the following then:

javascript
import { Navigate } from 'react-router-dom';

const withRedirectIfBlank = (config) => (Component) => (props) => {
  const { redirectCondition, redirectTo } = config;

  if (redirectCondition(props)) {
    return <Navigate replace to={redirectTo} />;
  }

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

export { withRedirectIfBlank };

Higher-Order Components are still useful these days, even though many React developers take them as legacy, because they are from a time when React Class Components where used. Especially when they are used to render conditional JSX. However, if not using any conditional JSX, using a Hook instead of a HOC is often a better design choice in modern React.

Never Miss an Article

Join 50,000+ developers getting weekly insights on full-stack engineering and AI.

AI Agentic UI Architecture React Next.js TypeScript Node.js Full-Stack Monorepos Product Engineering
Subscribe on Substack

High signal, low noise. Unsubscribe at any time.