Introduction
In modern React applications, navigation is not always triggered by clicking links. Often, developers need to navigate programmatically in response to user actions, such as submitting a form, logging in, completing a process, or dynamically redirecting users based on application logic.
React Router provides a useNavigate hook that enables programmatic navigation in functional components. This post will cover:
- Using the
useNavigatehook for navigation - Navigating after events like form submission
- Example: Redirecting users after successful login
- Replacing history entries versus pushing new entries
1. Using useNavigate Hook for Navigation
The useNavigate hook is provided by React Router v6+ and replaces the older useHistory hook from previous versions. It returns a function that allows you to navigate programmatically.
Basic Usage
import React from "react";
import { useNavigate } from "react-router-dom";
function Home() {
const navigate = useNavigate();
const goToAbout = () => {
navigate("/about");
};
return (
<div>
<h1>Home Page</h1>
<button onClick={goToAbout}>Go to About</button>
</div>
);
}
export default Home;
Explanation:
useNavigatereturns anavigatefunction.- Calling
navigate("/about")changes the route to/about. - Navigation can be triggered on any event (click, form submit, API success, etc.).
Navigate with Options
navigate can take a second argument with options:
navigate("/about", { replace: true, state: { from: "/home" } });
replace: truereplaces the current entry in the history stack.stateallows passing arbitrary data to the next route.
Example:
navigate("/dashboard", { replace: true, state: { userId: 123 } });
- Useful for redirecting users without leaving a back entry in history (e.g., after login).
2. Navigating After Events
Programmatic navigation is often used after user actions or events.
Example: Form Submission
import React, { useState } from "react";
import { useNavigate } from "react-router-dom";
function ContactForm() {
const [name, setName] = useState("");
const navigate = useNavigate();
const handleSubmit = (e) => {
e.preventDefault();
console.log("Form submitted:", name);
// After submission, navigate to thank-you page
navigate("/thank-you");
};
return (
<form onSubmit={handleSubmit}>
<input
type="text"
value={name}
onChange={(e) => setName(e.target.value)}
placeholder="Your Name"
/>
<button type="submit">Submit</button>
</form>
);
}
export default ContactForm;
Explanation:
- After form submission,
navigate("/thank-you")programmatically redirects the user. - No need for a
<Link>component.
Conditional Navigation
You can navigate based on conditions or API responses.
const handleLogin = async () => {
const response = await fakeLoginAPI(username, password);
if (response.success) {
navigate("/dashboard");
} else {
alert("Login failed");
}
};
- Navigation happens only if certain conditions are met.
3. Example: Redirecting Users After Successful Login
Step 1: Login Component
import React, { useState } from "react";
import { useNavigate } from "react-router-dom";
function Login() {
const [username, setUsername] = useState("");
const [password, setPassword] = useState("");
const navigate = useNavigate();
const handleLogin = (e) => {
e.preventDefault();
// Fake authentication logic
if (username === "admin" && password === "1234") {
navigate("/dashboard", { replace: true });
} else {
alert("Invalid credentials");
}
};
return (
<form onSubmit={handleLogin}>
<input
type="text"
placeholder="Username"
value={username}
onChange={(e) => setUsername(e.target.value)}
/>
<input
type="password"
placeholder="Password"
value={password}
onChange={(e) => setPassword(e.target.value)}
/>
<button type="submit">Login</button>
</form>
);
}
export default Login;
Step 2: Dashboard Component
import React from "react";
function Dashboard() {
return <h1>Welcome to the Dashboard!</h1>;
}
export default Dashboard;
Step 3: Routing Setup
import React from "react";
import { BrowserRouter as Router, Routes, Route } from "react-router-dom";
import Login from "./Login";
import Dashboard from "./Dashboard";
function App() {
return (
<Router>
<Routes>
<Route path="/" element={<Login />} />
<Route path="/dashboard" element={<Dashboard />} />
</Routes>
</Router>
);
}
export default App;
Explanation:
- After successful login, the user is redirected to
/dashboard. replace: trueensures that hitting the back button does not return the user to the login page.
4. Replacing History vs Pushing New Entries
Push New Entry
navigate("/dashboard");
- Adds a new entry to the browser history stack.
- Users can use the back button to return to the previous page.
- Useful when you want to maintain navigation history.
Replace Current Entry
navigate("/dashboard", { replace: true });
- Replaces the current history entry.
- Users cannot go back to the previous route using the back button.
- Ideal for login or redirect after submission where returning to the previous page is not desired.
Comparison:
| Method | History Stack Behavior | Use Case |
|---|---|---|
| Push (default) | Adds a new entry | Normal navigation between pages |
| Replace (true) | Replaces current entry | Login redirect, after form submission |
5. Navigating with State
useNavigate can pass state to the target route.
navigate("/dashboard", { state: { userId: 123, username: "admin" } });
Accessing state in the target component:
import { useLocation } from "react-router-dom";
function Dashboard() {
const location = useLocation();
console.log(location.state); // { userId: 123, username: "admin" }
return <h1>Dashboard for {location.state.username}</h1>;
}
- State is useful for passing non-URL information between routes.
6. Best Practices for Programmatic Navigation
- Use
replace: truefor login redirects – Prevents users from navigating back to the login page. - Use relative paths – Especially in nested routes.
- Handle edge cases – Check authentication before redirecting to protected routes.
- Pass state carefully – Avoid sensitive information in
state; use context or Redux for persistent global state. - Avoid navigating during render – Always navigate in event handlers or effects.
7. Real-World Use Cases
- Redirecting users after login or logout
- Navigating to confirmation or thank-you pages after form submission
- Conditional navigation based on user roles or permissions
- Dynamic routing in wizards or multi-step forms
Leave a Reply