This error occurs when the useNavigate hook or navigate() function is called outside the Router context. React Router hooks require components to be descendants of a Router component like BrowserRouter or RouterProvider.
This error occurs when you try to use React Router's navigation features (useNavigate hook or navigate function) in a component that is not wrapped by a Router component. React Router hooks rely on context provided by Router components like BrowserRouter, HashRouter, or RouterProvider to access routing functionality. The useNavigate hook internally uses React Context to access the routing state and navigation functions. When a component using this hook is not a descendant of a Router component, React cannot find the required context, resulting in this error. This commonly happens when: the Router is placed inside App.tsx instead of index.tsx, components using navigation hooks are rendered outside the Router tree, or during testing when components aren't properly wrapped in a Router.
The most common fix is to ensure your Router wraps your entire application at the root level. Move the Router component from App.tsx to your entry point:
// src/index.tsx
import { createRoot } from 'react-dom/client';
import { BrowserRouter } from 'react-router-dom';
import App from './App';
const rootElement = document.getElementById('root');
const root = createRoot(rootElement);
root.render(
<BrowserRouter>
<App />
</BrowserRouter>
);Your App.tsx should only contain Routes, not the Router wrapper:
// src/App.tsx
import { Routes, Route } from 'react-router-dom';
import Home from './pages/Home';
import About from './pages/About';
function App() {
return (
<Routes>
<Route path="/" element={<Home />} />
<Route path="/about" element={<About />} />
</Routes>
);
}
export default App;If using React Router v6.4+, prefer RouterProvider with createBrowserRouter for access to data APIs:
// src/main.tsx
import { createRoot } from 'react-dom/client';
import { createBrowserRouter, RouterProvider } from 'react-router-dom';
import Root from './routes/root';
import About from './routes/about';
import ErrorPage from './error-page';
const router = createBrowserRouter([
{
path: '/',
element: <Root />,
errorElement: <ErrorPage />,
},
{
path: '/about',
element: <About />,
},
]);
createRoot(document.getElementById('root')!).render(
<RouterProvider router={router} />
);Note: Do NOT pass children to RouterProvider - it only accepts the router prop.
When testing components that use navigation hooks, wrap them in a Router:
// Using React Testing Library
import { render, screen } from '@testing-library/react';
import { BrowserRouter } from 'react-router-dom';
import MyComponent from './MyComponent';
test('renders navigation component', () => {
render(
<BrowserRouter>
<MyComponent />
</BrowserRouter>
);
expect(screen.getByText('Navigate')).toBeInTheDocument();
});Or create a custom render helper:
// test-utils.tsx
import { ReactElement } from 'react';
import { render, RenderOptions } from '@testing-library/react';
import { BrowserRouter } from 'react-router-dom';
function customRender(
ui: ReactElement,
options?: Omit<RenderOptions, 'wrapper'>
) {
return render(ui, { wrapper: BrowserRouter, ...options });
}
export * from '@testing-library/react';
export { customRender as render };If you need to navigate from Redux actions, utility functions, or other non-React code, create a history helper:
// src/lib/navigation.ts
let navigate: ((to: string) => void) | null = null;
export function setNavigate(nav: (to: string) => void) {
navigate = nav;
}
export function navigateOutsideReact(to: string) {
if (navigate) {
navigate(to);
} else {
console.error('Navigate function not initialized');
}
}Initialize it in a component inside your Router:
// src/App.tsx
import { useEffect } from 'react';
import { useNavigate } from 'react-router-dom';
import { setNavigate } from './lib/navigation';
function App() {
const navigate = useNavigate();
useEffect(() => {
setNavigate(navigate);
}, [navigate]);
return (
{/* Your routes */}
);
}Now you can use it anywhere:
// Redux action or utility function
import { navigateOutsideReact } from './lib/navigation';
export function logoutUser() {
// Clear auth state
localStorage.removeItem('token');
// Navigate to login
navigateOutsideReact('/login');
}Ensure you don't have multiple Router components creating conflicting contexts:
BAD - Multiple routers:
// index.tsx
<BrowserRouter>
<App />
</BrowserRouter>
// App.tsx (WRONG - creates nested Router)
<BrowserRouter>
<Routes>...</Routes>
</BrowserRouter>GOOD - Single router:
// index.tsx
<BrowserRouter>
<App />
</BrowserRouter>
// App.tsx (Correct - no Router wrapper)
<Routes>
<Route path="/" element={<Home />} />
</Routes>Search your codebase for all instances of BrowserRouter, HashRouter, MemoryRouter, and RouterProvider to identify duplicates.
React Router v6.4+ Data APIs: If using loaders, actions, or other data features introduced in React Router v6.4, you must use createBrowserRouter with RouterProvider. The older BrowserRouter component doesn't support these features.
Memory Router for Testing: For more complex test scenarios, consider using MemoryRouter instead of BrowserRouter, as it doesn't require a DOM and allows you to control the history state:
import { MemoryRouter } from 'react-router-dom';
<MemoryRouter initialEntries={['/profile']}>
<MyComponent />
</MemoryRouter>Server-Side Rendering: When using React Router with SSR frameworks like Remix or Next.js with React Router, use StaticRouter on the server side and ensure client-side hydration uses the appropriate browser router.
Navigation After Authentication: A common pattern is redirecting after login. Ensure your authentication logic either happens inside a component within the Router tree, or use the history helper pattern described above to navigate from authentication utilities.
Strict Mode Double Mounting: React 18's Strict Mode intentionally double-mounts components in development. This doesn't cause the Router context error but may reveal issues with navigation side effects. Use cleanup functions in useEffect to prevent duplicate navigation calls.
Prop spreading could cause security issues
Prop spreading could cause security issues
Error: error:0308010C:digital envelope routines::unsupported
Error: error:0308010C:digital envelope routines::unsupported
React Hook "useEffect" is called conditionally. React Hooks must be called in the exact same order in every component render.
React Hook useEffect placed inside a condition
Hook can only be called inside the body of a function component
Hook can only be called inside the body of a function component
Rollup failed to resolve import during build
How to fix "Rollup failed to resolve import" in React