Routing is a core part of building any single-page application in React, and with React Router v6, the experience is smoother and more powerful than ever. One essential hook in this version is useNavigate
, which replaces older patterns like useHistory
from React Router v5. This hook allows you to programmatically navigate between routes, making it especially useful in event handlers, form submissions, or after a successful API call.
In this blog, I’ll walk you through how useNavigate
works, how I use it in different scenarios, and the best practices I follow when navigating users in my React apps.
useNavigate
is a hook provided by React Router v6. It returns a function that lets you navigate to a new route in your application. Unlike the older history.push()
or history.replace()
methods from React Router v5, useNavigate
is more concise and built specifically for functional components.
It works within components that are inside a <Router>
(usually <BrowserRouter>
), and it lets me redirect the user anywhere based on interaction or logic.
Setting Up React Router v6
To use useNavigate
, I first make sure my app is wrapped with BrowserRouter
. Here’s a basic setup I typically use:
import { BrowserRouter, Routes, Route } from 'react-router-dom'
import Home from './pages/Home'
import About from './pages/About'
function App() {
return (
<BrowserRouter>
<Routes>
<Route path="/" element={<Home />} />
<Route path="/about" element={<About />} />
</Routes>
</BrowserRouter>
)
}
Once the router is set up, I can use useNavigate
in any component rendered inside this router context.
When I want to redirect a user from one page to another, maybe after clicking a button, I call the navigate
function returned by useNavigate
.
import { useNavigate } from 'react-router-dom'
function Home() {
const navigate = useNavigate()
const handleClick = () => {
navigate('/about')
}
return (
<div>
<h1>Home Page</h1>
<button onClick={handleClick}>Go to About</button>
</div>
)
}
This is my go-to pattern when I need a programmatic redirect. For example, if a user clicks a button, logs in successfully, or finishes a multi-step form, I use this to take them to the next screen.
Replacing the Current Entry in History
Sometimes I don’t want the user to be able to go back to the previous page. For example, after a login or logout, pressing the browser back button shouldn’t bring them back to the login form. In such cases, I use the replace
option.
navigate('/dashboard', { replace: true })
This is one of the best tricks I use for post-auth redirects. It replaces the current entry in the browser history stack rather than pushing a new one, keeping the user flow clean and secure.
useNavigate
also lets me pass state to the target route. This is useful when I want to send data without putting it in the URL.
navigate('/profile', { state: { userId: 42 } })
On the receiving component, I grab this state using the useLocation
hook.
import { useLocation } from 'react-router-dom'
function Profile() {
const location = useLocation()
const { userId } = location.state || {}
return <p>User ID: {userId}</p>
}
This pattern helps me avoid query strings or global state when passing simple parameters between pages.
Redirecting After Form Submission
When I handle forms in React, I often navigate the user to a confirmation page after a successful submission. Here’s an example I commonly use:
function ContactForm() {
const navigate = useNavigate()
const handleSubmit = (e) => {
e.preventDefault()
// form validation and API call here...
navigate('/thank-you')
}
return (
<form onSubmit={handleSubmit}>
<input name="name" placeholder="Your Name" />
<button type="submit">Submit</button>
</form>
)
}
This approach keeps the logic simple and makes the form feel responsive. It also avoids unnecessary reloads.
In authentication workflows, I use conditional checks before navigating the user. If they’re not logged in, I might redirect them to the login page.
const isAuthenticated = checkAuth()
if (!isAuthenticated) {
navigate('/login')
}
However, I wrap this inside useEffect
or an event handler to avoid redirecting during rendering.
useEffect(() => {
if (!isAuthenticated) {
navigate('/login')
}
}, [])
Using navigate
inside useEffect
has been a great way for me to redirect users based on state or props.
Besides navigating to a specific route, I can also go back or forward in the user’s browser history stack.
navigate(-1) // go back
navigate(1) // go forward
I use this when building wizard-style forms or in components with back buttons. It’s simple and uses the browser’s native navigation.
To keep my code DRY, I sometimes wrap useNavigate
inside a custom hook. For example:
function useGoToDashboard() {
const navigate = useNavigate()
return () => navigate('/dashboard', { replace: true })
}
Then I use it like this:
const goToDashboard = useGoToDashboard()
goToDashboard()
This helps me standardize redirects across my app and keep my components cleaner.
Summary
React Router v6’s useNavigate
hook has made routing in my React apps more intuitive and powerful. Whether I’m redirecting after a user action, replacing history, or passing state between routes, useNavigate
gives me a clear and consistent way to handle navigation.
By using it smartly—within event handlers, conditionally after side effects, or with route state—I’ve managed to keep my routing logic simple, testable, and clean. If you’re just starting with React Router v6 or migrating from earlier versions, mastering useNavigate
will definitely level up your navigation game.