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.

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.