Navigation in React: Not Just a Link Click
\n\nHave you ever wondered how to make React Router navigate to another page not by a user click, but by a command from code? For example, after a successful form submission, authentication, or just after 5 seconds? If so, you've come to the right place. The question "How can I programmatically navigate using React Router?" is one of the most popular on Stack Overflow, and for good reason. It seems simple, but in reality, there are many pitfalls, especially when it comes to performance.
\n\nIn this article, we won't just show you how to use useNavigate. We'll break down how to do it correctly, quickly, and without lag. You'll learn which patterns lead to memory leaks and which lead to lightning-fast navigation. Let's go!
The Classic: useNavigate — Your Main Tool
\n\nStarting with React Router v6, useNavigate replaced the old useHistory. This is a hook that returns the navigate function. It looks like this:
import { useNavigate } from 'react-router-dom';\n\nfunction LoginButton() {\n const navigate = useNavigate();\n\n const handleLogin = () => {\n // Authentication logic here\n const user = { name: 'Ivan' };\n // After success — redirect\n navigate('/dashboard', { replace: true });\n };\n\n return <button onClick={handleLogin}>Log In</button>;\n}\n\n\nNote the parameter { replace: true }. It replaces the current entry in history, rather than adding a new one. This is critical for login, so the user doesn't go back to the login page.
Where can you navigate?
\n- \n
- Absolute path:
navigate('/about')\n - Relative path:
navigate('../settings')\n - Back/forward in history:
navigate(-1)ornavigate(2)\n
Advanced Level: Navigation Outside Components
\n\nWhat if you need to redirect from a regular function, not inside a React component? For example, from an action creator in Redux or from an axios interceptor? The useNavigate hook won't work here — hooks are only called inside functional components.
Solution: create a custom wrapper component or use a global router object. In React Router v6, there is a special component RouterProvider and createBrowserRouter for this, but there is also a simpler way — save a reference to navigate in a variable.
// router.js\nimport { createBrowserRouter, RouterProvider } from 'react-router-dom';\n\nexport const router = createBrowserRouter([...]);\n\n// navigation.js — a separate module for navigation\nlet navigateFunction = null;\n\nexport const setNavigate = (navigate) => {\n navigateFunction = navigate;\n};\n\nexport const navigateTo = (path) => {\n if (navigateFunction) {\n navigateFunction(path);\n } else {\n console.warn('Navigation is not ready yet');\n }\n};\n\n// App.js\nimport { useNavigate } from 'react-router-dom';\nimport { setNavigate } from './navigation';\nimport { useEffect } from 'react';\n\nfunction App() {\n const navigate = useNavigate();\n\n useEffect(() => {\n setNavigate(navigate);\n }, [navigate]);\n\n return /* your code */;\n}\n\n\nNow from any function (whether from setTimeout or fetch), you can call navigateTo('/home'). Convenient? Yes. Safe? Only if you don't forget to clear the reference when the component unmounts.
Performance Optimization: Why Is Your Application Lagging?
\n\nProgrammatic navigation is not just a function call. It is a trigger for a full page re-render. And if you do this