React: useNavigate() may be used only in the context of a Router component

The ReactJS error “useNavigate() may be used only in the context of a Router component” occurs when you try to use the useNavigate hook outside a <BrowserRouter> or <HashRouter> component. To fix this, move your <*Router> tags to a higher level component.

This error was discovered when working on our SuperTokens tutorial. If you want to learn more about how to secure your apps without having to implement your own user management, be sure to check out that article.

A popular library for implementing frontend routing in React is react-router-dom. It’s pretty simple to use, however, there are some rules you have to follow. One of those is making sure that all things that need to use the router occur inside the router component’s tags.

Let’s look at an example.

Problem: you’re using useNavigate outside the router

Let’s say you have a chat app that has a users page (we’re using code from our GraphQL chat app example – check it out). For some reason, you want to use a button instead of a simple link to go to the users page. Below is an example of how you’d do that:

import { Provider } from "urql";
import { urqlClient } from "./utils";
import { HashRouter, Route, Routes, Link, useNavigate } from "react-router-dom";

import MessagesPage from "./MessagesPage";
import UsersPage from "./UsersPage";

function App() {
    const navigate = useNavigate();
    const logIn = () => {
        navigate("/users");
    };

    return (
        <Provider value={urqlClient}>
            <HashRouter>
                <div id="menu">
                    Menu: 
                    <Link to="/">Home</Link> 
                    <button onClick={logIn}>Users</button>
                </div>
                <Routes>
                    <Route path="/" element={<MessagesPage />} />
                    <Route path="/users" element={<UsersPage />} />
                </Routes>
            </HashRouter>
        </Provider>
    );
}

export default App;
JavaScript

We use react-router-dom‘s built-in hook useNavigate to send the user to a the users page when they click our button. This all looks like it should work, but if you were to compile and run this, you’d get a blank page and the following error in your dev console:

So what happened here? I’ve highlighted the problem below:

import { Provider } from "urql";
import { urqlClient } from "./utils";
import { HashRouter, Route, Routes, Link, useNavigate } from "react-router-dom";

import MessagesPage from "./MessagesPage";
import UsersPage from "./UsersPage";

function App() {
    const navigate = useNavigate();
    const logIn = () => {
        navigate("/users");
    };

    return (
        <Provider value={urqlClient}>
            <HashRouter>
                <div id="menu">
                    Menu: 
                    <Link to="/">Home</Link> 
                    <button onClick={logIn}>Users</button>
                </div>
                <Routes>
                    <Route path="/" element={<MessagesPage />} />
                    <Route path="/users" element={<UsersPage />} />
                </Routes>
            </HashRouter>
        </Provider>
    );
}

export default App;
JavaScript

As the error says, you used the useNavigate hook outside of a router. Here, we’re using the <HashRouter> component, which is our router. We’re also trying to use useNavigate up there at the top of our main App component. The problem is, that’s outside of a router, which means useNavigate doesn’t have access to the context info it needs to route you. In fact, it has no idea about any of the routes you created in the render portion of this component.

Solution: move your router tags to a higher level component

The way we fix this is simple. We just have to move the HashRouter to a higher level. In our app, since we used create-react-app to make it, that means putting the <HashRouter> tags up in the index.js file like so:

import React from 'react';
import ReactDOM from 'react-dom/client';
import App from './App';
import { HashRouter } from "react-router-dom";

const root = ReactDOM.createRoot(document.getElementById('root'));
root.render(
  <React.StrictMode>
    <HashRouter>
        <App />
    </HashRouter>
  </React.StrictMode>
);
JavaScript

Now, our entire app is covered by the <HashRouter> context, and will function correctly:

Conclusion

In this article, we discussed what causes the ReactJS error “useNavigate() may be used only in the context of a Router component” and how to solve it. In a nutshell, your react-router-dom router component (either <BrowserRouter> or <HashRouter>) needs to be at a high enough level in your component tree so that any components using router functions are contained within it.