Navigate vs useNavigate in React Router DOM: Differences and When to Use Each

Use the <Navigate> component for declarative redirects that occur during rendering, and the useNavigate hook for imperative navigation triggered by event handlers, effects, or asynchronous callbacks.

While the facebook/react repository provides the core primitives that power React applications, it does not contain the React Router DOM implementation. The Navigate component and useNavigate hook are defined in the separate react-router-dom package. However, analyzing how React core handles navigation concepts—such as in packages/react-dom/src/client/ReactDOMDefaultTransitionIndicator.js—helps clarify the architectural distinction between declarative and imperative routing patterns.

Core Differences Between Navigate and useNavigate

React Router DOM offers two primary APIs for changing the current location: a JSX component that renders a redirect, and a hook that returns a navigation function.

<Navigate> is a component that triggers a redirect immediately when it is rendered into the component tree. It replaces the current entry or pushes a new entry onto the browser's history stack based on its props.

Because it is a component, it must be returned from a component's render output or placed in JSX. It is ideal for conditional guards that depend on the current render state, such as authentication checks.

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

function PrivateRoute({ children, isAuthenticated }) {
  return isAuthenticated ? children : <Navigate to="/login" replace />;
}

When this component mounts, the router immediately navigates to the to prop value. The replace prop determines whether the current history entry is replaced rather than pushing a new entry.

useNavigate: Imperative Hook Navigation

useNavigate is a React hook that returns a navigate function. This function can be called programmatically anywhere inside your component logic—including inside useEffect hooks, event handlers, or callbacks—rather than being rendered as JSX.

The returned function accepts a to location string or number (for delta navigation) and an optional options object containing replace and state properties.

import { useNavigate } from 'react-router-dom';

function LoginButton() {
  const navigate = useNavigate();
  
  const handleLogin = async (credentials) => {
    const result = await api.login(credentials);
    if (result.success) {
      navigate('/dashboard', { replace: true });
    }
  };
  
  return <button onClick={handleLogin}>Log In</button>;
}

Specific Use Cases for useNavigate in React

Choosing useNavigate over <Navigate> depends on when and where the navigation needs to occur.

  • Navigation after side effects: Call useNavigate inside useEffect or after an asynchronous operation (like a form submission or API call) completes. This is impossible with <Navigate>, which would cause an immediate redirect during the render phase.
  • Event handler navigation: Button clicks, form submissions, or keyboard events require the imperative approach. The hook allows you to call navigate() inside the handler function rather than conditionally rendering a component.
  • Complex conditional logic: When navigation depends on state calculations that happen after the component mounts or updates, useNavigate lets you defer the decision until the appropriate moment, avoiding premature redirects during render.

For simple "guard" redirects that can be evaluated immediately during render—such as redirecting unauthenticated users away from a protected route—the <Navigate> component provides a cleaner, more declarative syntax.

Practical Implementation Examples

Declarative Auth Guard with Navigate

Use <Navigate> when the redirect logic is synchronous and directly tied to the render output.

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

function AdminPanel({ user }) {
  if (!user.isAdmin) {
    return <Navigate to="/unauthorized" replace />;
  }
  return <div>Admin Dashboard</div>;
}

Form Submission with useNavigate

Use useNavigate when navigation must occur after an asynchronous operation or user interaction.

import { useNavigate } from 'react-router-dom';
import { useState } from 'react';

function SearchForm() {
  const [query, setQuery] = useState('');
  const navigate = useNavigate();

  const handleSubmit = (e) => {
    e.preventDefault();
    navigate(`/search?q=${encodeURIComponent(query)}`);
  };

  return (
    <form onSubmit={handleSubmit}>
      <input 
        value={query} 
        onChange={(e) => setQuery(e.target.value)} 
      />
      <button type="submit">Search</button>
    </form>
  );
}

useNavigate is essential when redirecting based on data loaded inside useEffect.

import { useNavigate } from 'react-router-dom';
import { useEffect, useState } from 'react';

function Checkout() {
  const navigate = useNavigate();
  const [orderId, setOrderId] = useState(null);

  useEffect(() => {
    async function createOrder() {
      const id = await api.createOrder();
      setOrderId(id);
    }
    createOrder();
  }, []);

  useEffect(() => {
    if (orderId) {
      navigate(`/order-confirmation/${orderId}`, { replace: true });
    }
  }, [orderId, navigate]);

  return <p>Processing your order...</p>;
}

React Core vs. React Router: Source Context

The facebook/react repository does not contain the source for <Navigate> or useNavigate. These are implemented in the separate remix-run/react-router package. However, React core does include experimental support for the Web Navigation API in files such as:

These internal files handle low-level browser navigation events (like navigatesuccess and navigateerror) for React's experimental concurrent features, but they are unrelated to the routing abstractions provided by React Router DOM.

Summary

  • <Navigate> is a component for declarative redirects that executes during the render phase when a condition is met.
  • useNavigate is a hook for imperative navigation that returns a function to be called inside event handlers, effects, or callbacks.
  • Use useNavigate when navigation depends on asynchronous operations, user interactions, or side effects that occur after rendering.
  • Use <Navigate> for simple, synchronous auth guards or conditional redirects that can be determined immediately during render.
  • The actual implementation resides in react-router-dom, not in the facebook/react core repository.

Frequently Asked Questions

Can I use Navigate inside an event handler or useEffect?

No. <Navigate> is a component that must be rendered in JSX. If you try to use it inside an event handler or useEffect, it will not work because you cannot render components from within those contexts. For programmatic navigation outside of the render cycle, you must use the useNavigate hook.

Is useNavigate available in React Router v5?

No. useNavigate was introduced in React Router v6. In React Router v5, you would use the useHistory hook, which provided a history object with push and replace methods. Migration from v5 to v6 requires replacing useHistory().push('/path') with useNavigate()('/path').

What happens if I call useNavigate during the component render phase?

Calling the navigate function returned by useNavigate during the component render is not supported and will throw an error. Navigation must be triggered from within an event handler, a useEffect, or another callback. For redirects during rendering, use the <Navigate> component instead.

Does the facebook/react repository contain React Router's source code?

No. The React Router library (including Navigate and useNavigate) is maintained in a separate repository (remix-run/react-router). The facebook/react repository contains the core React library and experimental Web Navigation API support in files like packages/react-dom/src/client/ReactDOMDefaultTransitionIndicator.js, but these are unrelated to React Router's routing components.

Have a question about this repo?

These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:

Share the following with your agent to get started:
curl -s https://instagit.com/install.md

Works with
Claude Codex Cursor VS Code OpenClaw Any MCP Client