When to Avoid useNavigate Hook in React
The useNavigate hook from React Router is a powerful
tool for programmatic navigation, but using it inappropriately can harm
your application’s accessibility, SEO, and user experience. This article
explores the specific scenarios where you should avoid
useNavigate in favor of standard HTML links, declarative
components, or other routing strategies, ensuring your React
applications remain accessible and performant.
1. For Standard Link Navigation (User-Initiated Clicks)
You should avoid using useNavigate inside an
onClick event handler on non-interactive elements (like
<div> or <span>) or even buttons
when you are simply directing a user to a new page.
Using programmatic navigation instead of a standard
<Link> component breaks fundamental web behavior: *
Accessibility (a11y): Screen readers do not recognize
these elements as navigation links, making your site difficult to
navigate for visually impaired users. * SEO
Crawlability: Search engine bots cannot follow JavaScript click
events initiated by useNavigate. If your site relies on
this for navigation, search engines will fail to index your subpages. *
User Experience: Users cannot right-click to “Open link
in new tab” or Cmd/Ctrl+click to open the page in the background.
What to use instead: Use React Router’s
<Link> or <NavLink>
components.
// AVOID THIS:
<button onClick={() => navigate('/about')}>About Us</button>
// DO THIS:
<Link to="/about">About Us</Link>2. During the Initial Render or Inside useEffect for Redirects
Using useNavigate inside a useEffect hook
to redirect users immediately upon rendering a component (such as
redirecting unauthorized users to a login page) can lead to a poor user
experience.
This approach often causes a “flash of unauthorized content” before the redirect occurs because the component must mount first before the effect runs.
What to use instead: * Declarative
Redirects: Use the <Navigate> component
directly in your render tree or routing configuration. * Route
Loaders: If you are using React Router v6.4+, handle
authentication and redirects on the server or route level using
loader functions. This prevents the component from
rendering entirely if the user is not authorized.
// AVOID THIS:
useEffect(() => {
if (!isAuthenticated) {
navigate('/login');
}
}, [isAuthenticated]);
// DO THIS (React Router v6 Data APIs):
export const loader = async () => {
const user = await checkAuth();
if (!user) {
return redirect("/login");
}
return null;
};3. For Navigating to External Websites
The useNavigate hook is designed strictly for internal
client-side routing within your Single Page Application (SPA). If you
attempt to pass an external URL (like https://google.com)
to useNavigate, React Router will treat it as a relative
path and append it to your current domain (e.g.,
yourdomain.com/https://google.com), resulting in a 404
error.
What to use instead: Use a standard HTML anchor tag
(<a>) for external links.
// AVOID THIS:
navigate('https://external-site.com');
// DO THIS:
<a href="https://external-site.com" target="_blank" rel="noopener noreferrer">
Visit External Site
</a>4. Outside of React Components and Context
Because useNavigate is a React Hook, it is subject to
the Rules of Hooks. You cannot call it inside regular JavaScript files,
Redux helper files, Axios interceptors, or state management middleware.
Attempting to do so will result in a runtime crash.
What to use instead: * If you need to redirect a
user globally (e.g., when an API returns a 401 Unauthorized error in an
Axios interceptor), you should use a custom history object, pass the
navigate function as a callback, or use
window.location.replace('/login') for a full-page reload if
necessary.