When we try to use the useNavigate hook outside the Router context of a react router, we get the warning “useNavigate() may be used only in the context of a Router component”. To fix this issue, you can only use the useNavigate hook in the Router context.

react error

Here is an example of wrapping a React application in a Router in the index.js file.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
// index.js
import {createRoot} from 'react-dom/client';
import App from './App';
import {BrowserRouter as Router} from 'react-router-dom';

const rootElement = document.getElementById('root');
const root = createRoot(rootElement);

// 👇️ wrap App in Router

root.render(
  <Router>
    <App />
  </Router>
);

useNavigate

Now, you can use the useNavigate hook in the App.js file.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
// App.js
import React from 'react';
import {
  useNavigate,
} from 'react-router-dom';

export default function App() {
  const navigate = useNavigate();

  const handleClick = () => {
    // 👇️ navigate programmatically
    navigate('/about');
  };

  return (
    <div>
      <button onClick={handleClick}>Navigate to About</button>
    </div>
  );
}

The error occurs because the useNavigate hook uses the context provided by the Router component, so it must be nested inside the Router.

The best place to wrap your React application with a Router component is in your index.js file, because that is the entry point to your React application.

Once your entire application is wrapped in a Router component, you can use the hooks provided by the react router in the component whenever and wherever you want.

Jest

If you encounter an error while using the Jest test library, the solution is the same. You must wrap the component that uses the useNavigate hook in a Router.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
// App.test.js
import {render} from '@testing-library/react';
import App from './App';
import {BrowserRouter as Router} from 'react-router-dom';

// 👇️ wrap component that uses useNavigate in Router

test('renders react component', async () => {
  render(
    <Router>
      <App />
    </Router>,
  );

  // your tests...
});

The useNavigate hook returns a function that allows us to programmatically route jumps, for example after a form submission.

The arguments we pass to the navigate function are the same as the to attribute on the <Link to="/about"> component.

replace

If you want to use the equivalent of history.replace(), pass a configuration parameter to the navigate function.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
// App.js
import {useNavigate} from 'react-router-dom';

export default function App() {
  const navigate = useNavigate();

  const handleClick = () => {
    // 👇️ replace set to true
    navigate('/about', {replace: true});
  };

  return (
    <div>
      <button onClick={handleClick}>Navigate to About</button>
    </div>
  );
}

When the value of the replace property is set to true in the configuration object, the current entry in the browser history stack is replaced by a new entry.

In other words, navigating to a new route this way does not push in a new entry in the browser history stack. So if the user clicks the back button, it does not navigate to the previous page.

This is very useful. For example, when the user is logged in, you don’t want the user to be able to click the back button and go back to the login page again. Or say there is a route to redirect to another page and you don’t want the user to click the back button and thus be redirected again.

You can also use numeric calls to the navigate function to achieve the effect of going back from the history stack. For example, navigate(-1) would be equivalent to pressing the back button.