Skip to content

React Router v6 Redirects

React Router v6 introduced significant changes to how redirects and routing work. If you're migrating from v5 or learning v6 for the first time, understanding the proper redirect patterns is essential.

Problem: The v5 to v6 Migration Challenge

In React Router v5, you might have used the Redirect component or the render prop on Route components:

jsx
// v5 syntax (no longer works in v6)
<Route render={() => <Redirect to="/" />} />

However, in v6, this approach results in a TypeScript error because the render prop no longer exists on Route components:

TS2322: Type '{ render: () => Element; }' is not assignable to type 'IntrinsicAttributes & (PathRouteProps | LayoutRouteProps | IndexRouteProps)'. Property 'render' does not exist on type 'IntrinsicAttributes & (PathRouteProps | LayoutRouteProps | IndexRouteProps)'.

Solution: Using the Navigate Component

React Router v6 replaces the Redirect component with Navigate. Here's the correct way to handle redirects:

Basic Redirect with Navigate

jsx
import { BrowserRouter, Navigate, Route, Routes } from 'react-router-dom';

<BrowserRouter>
  <Routes>
    <Route path="/" element={<Home />} />
    <Route path="/lab" element={<Lab />} />
    <Route path="*" element={<Navigate to="/" replace />} />
  </Routes>
</BrowserRouter>

The replace prop is important—it replaces the current entry in the history stack instead of adding a new one, preventing unwanted back/forward navigation issues.

Conditional Redirects

You can conditionally redirect users based on application state:

jsx
<Route 
  path="/dashboard" 
  element={user ? <Dashboard /> : <Navigate to="/login" replace />} 
/>

Programmatic Navigation with useNavigate

For navigation triggered by user interactions or other events, use the useNavigate hook:

jsx
import { useNavigate } from "react-router-dom";

function MyComponent() {
  const navigate = useNavigate();
  
  const handleClick = () => {
    // Redirect programmatically
    navigate("/target-path", { replace: true });
  };
  
  return (
    <button onClick={handleClick}>Go to target</button>
  );
}

Redirect with Route Parameters

If you need to redirect while preserving URL parameters, create a custom redirect component:

jsx
// Redirect.tsx
import { useEffect } from 'react'
import { generatePath, useNavigate, useParams } from 'react-router-dom'

function Redirect({ to }: { to: string }) {
  const navigate = useNavigate()
  const params = useParams()

  useEffect(() => {
    navigate(generatePath(to, params), { replace: true })
  })

  return null
}

export default Redirect

Usage:

jsx
<Route path="/users/:id" element={<Redirect to="/new-path/:id" />} />

Authentication Guard Pattern

For protecting routes that require authentication, create a wrapper component:

jsx
// RequireAuth.tsx
import { useLocation, Navigate } from "react-router-dom";
import { useAuth } from "../hooks/Auth";

export function RequireAuth({ children }: { children: JSX.Element }) {
  let { user } = useAuth();
  let location = useLocation();

  if (!user) {
    return <Navigate to="/login" state={{ from: location }} replace />;
  }
  
  return children;
}

Usage:

jsx
<Route
  path="/dashboard"
  element={
    <RequireAuth>
      <Dashboard />
    </RequireAuth>
  }
/>

Common Use Cases

Redirecting from Index Route

jsx
<Routes>
  <Route path="/home" element={<Home />} />
  <Route path="/about" element={<About />} />
  <Route index element={<Navigate to="/home" replace />} />
</Routes>

Catch-all Route for 404 Scenarios

jsx
<Routes>
  <Route path="/" element={<Home />} />
  <Route path="/about" element={<About />} />
  <Route path="*" element={<NotFound />} />
</Routes>

Migration Tips

WARNING

When migrating from v5, remember that:

  • Redirect is replaced with Navigate
  • The render prop is removed from Route
  • The component prop is replaced with element
  • Use the useNavigate hook instead of useHistory

Best Practices

  1. Use replace for redirects to avoid cluttering the browser history
  2. Handle authentication at the route level using protective wrappers
  3. Preserve URL parameters when redirecting to similar routes
  4. Provide a fallback route for undefined paths

By following these patterns, you can effectively handle redirects in React Router v6 while maintaining clean, maintainable code.