React Router: Redirect with Higher-Order Component
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:
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.
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:
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:
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.