Migrating from <Redirect>
to <Navigate>
in React Router v6
React Router v6 replaced the <Redirect>
component with the more flexible <Navigate>
component. This change reflects a shift toward a more declarative and hook-based API.
The Problem: Using <Redirect>
in v6
In React Router v6, this code won’t work:
import { Redirect } from 'react-router-dom';
function PrivateRoute({ user }) {
if (!user) {
return <Redirect to="/login" />; // ❌ Not available in v6
}
return <Dashboard />;
}
The Solution: Using <Navigate>
Here’s the correct v6 approach:
import { Navigate } from 'react-router-dom';
function PrivateRoute({ user }) {
if (!user) {
return <Navigate to="/login" replace />; // ✅ Correct v6 approach
}
return <Dashboard />;
}
Key Differences
Feature | <Redirect> (v5) | <Navigate> (v6) |
---|---|---|
Import | react-router-dom | react-router-dom |
Behavior | Immediate redirect | Immediate redirect |
Props | to , push | to , replace , state |
Usage | In route config or components | Primarily in components |
Type Support | Basic | Better TypeScript integration |
Common Migration Scenarios
1. Basic Redirect
v5:
<Redirect from="/old" to="/new" />
v6:
<Route path="/old" element={<Navigate to="/new" replace />} />
2. Conditional Redirect
v5:
function Component() {
return isLoggedIn ? <Dashboard /> : <Redirect to="/login" />;
}
v6:
function Component() {
return isLoggedIn ? <Dashboard /> : <Navigate to="/login" replace />;
}
3. Redirect with State
v5:
<Redirect
to={{
pathname: "/login",
state: { from: location }
}}
/>
v6:
<Navigate
to="/login"
replace
state={{ from: location }}
/>
Advanced Patterns
1. Protected Routes
function ProtectedRoute({ children }) {
const { user } = useAuth();
const location = useLocation();
if (!user) {
return <Navigate to="/login" replace state={{ from: location }} />;
}
return children;
}
// Usage
<Route
path="/dashboard"
element={
<ProtectedRoute>
<Dashboard />
</ProtectedRoute>
}
/>
2. Route-Based Redirects
<Routes>
<Route path="/" element={<Home />} />
<Route path="/old-route" element={<Navigate to="/new-route" replace />} />
<Route path="/new-route" element={<NewComponent />} />
</Routes>
3. Maintaining History
By default, <Navigate replace>
replaces the current history entry. To push instead:
<Navigate to="/new-location" /> {/* Defaults to replace={false} */}
Common Mistakes
❌ Forgetting the replace
Prop
<Navigate to="/login" /> {/* Creates new history entry */}
✅ Fix: Use replace
for redirect behavior
<Navigate to="/login" replace /> {/* Replaces current entry */}
❌ Using in Route Config Without Element
<Route path="/old" navigate="/new" /> {/* ❌ Invalid */}
✅ Fix: Wrap in element prop
<Route path="/old" element={<Navigate to="/new" replace />} />
❌ Mixing v5 and v6 Patterns
<Route
path="/old"
element={<Redirect to="/new" />} {/* ❌ Mixing components */}
/>
TypeScript Support
<Navigate>
has excellent TypeScript support:
<Navigate
to="/dashboard"
replace
state={{ from: "homepage" }} // Type-checked
/>
Key Takeaways
- Replace
<Redirect>
with<Navigate>
in v6 - Use
replace
prop to mimic v5 redirect behavior - Pass state through the
state
prop - TypeScript works better with the new component
- Declare redirects in route config using the
element
prop
The <Navigate>
component provides a more flexible and consistent way to handle redirects in React Router v6, with better integration with hooks and TypeScript. While it requires some changes from v5 patterns, the improved API design makes the migration worthwhile.