Using history.push() in React Router v6 instead of useNavigate()

React Router v6 introduced significant changes to its navigation API, replacing the history object with the useNavigate() hook. This change often causes confusion for developers migrating from v5 or trying to use old patterns in v6.

Key Differences Between v5 and v6

FeatureReact Router v5React Router v6
Navigation methodhistory.push()useNavigate()
Access methoduseHistory() hookuseNavigate() hook
Relative pathsLimited supportFull support
API styleObject-based (history)Function-based (navigate)

The Problem: Using history.push() in v6

In React Router v6, this code won’t work:

import { useHistory } from 'react-router-dom';

function MyComponent() {
  const history = useHistory(); // ❌ Not available in v6

  const handleClick = () => {
    history.push('/new-route'); // ❌ Old pattern
  };

  return <button onClick={handleClick}>Go</button>;
}

The Solution: Using useNavigate()

Here’s how to properly navigate in v6:

import { useNavigate } from 'react-router-dom';

function MyComponent() {
  const navigate = useNavigate(); // ✅ Correct v6 approach

  const handleClick = () => {
    navigate('/new-route'); // ✅ Uses the new API
  };

  return <button onClick={handleClick}>Go</button>;
}

Common Migration Scenarios

1. Basic Navigation

v5:

history.push('/dashboard');

v6:

navigate('/dashboard');

2. Navigation with State

v5:

history.push('/user', { userData: 123 });

v6:

navigate('/user', { state: { userData: 123 } });

3. Replace Instead of Push

v5:

history.replace('/login');

v6:

navigate('/login', { replace: true });

4. Relative Navigation

v5:

history.push(`${match.url}/details`);

v6 (better relative navigation):

navigate('details'); // Relative to current route

Advanced Patterns

1. Programmatic Navigation Outside Components

For navigation in Redux actions or services:

// Create a history instance (only do this once in your app)
import { createBrowserHistory } from 'history';
export const history = createBrowserHistory();

// In your app setup
import { unstable_HistoryRouter as HistoryRouter } from 'react-router-dom';
import { history } from './history';

<HistoryRouter history={history}>
  <App />
</HistoryRouter>

// Then use anywhere in your app
history.push('/somewhere');

2. Using Navigate Component

For conditional redirects in JSX:

import { Navigate } from 'react-router-dom';

function ProtectedRoute({ user }) {
  if (!user) {
    return <Navigate to="/login" replace />;
  }
  return <Dashboard />;
}

3. Custom Navigation Hook

Create a reusable hook:

import { useNavigate } from 'react-router-dom';

export function useNavigation() {
  const navigate = useNavigate();

  const goTo = (path, options = {}) => {
    navigate(path, options);
  };

  return { goTo };
}

// Usage
const { goTo } = useNavigation();
goTo('/products');

Handling Common Errors

Error: “useNavigate() may be used only in the context of a component”

Solution: Wrap your app with a router:

import { BrowserRouter } from 'react-router-dom';

ReactDOM.render(
  <BrowserRouter>
    <App />
  </BrowserRouter>,
  document.getElementById('root')
);

Error: “history.push is not a function”

Solution: You’re mixing v5 and v6 patterns. Stick to useNavigate() in v6.

Backward Compatibility

If you need to maintain both v5 and v6 during migration:

// navigation-utils.js
import { useNavigate } from 'react-router-dom';

export function useLegacyNavigation() {
  const navigate = useNavigate();

  return {
    push: (path, state) => navigate(path, { state }),
    replace: (path) => navigate(path, { replace: true }),
    // Add other history methods as needed
  };
}

// Usage
const history = useLegacyNavigation();
history.push('/old-path');

Key Takeaways

  1. React Router v6 replaces history.push() with useNavigate()
  2. The new API is more consistent and supports better relative navigation
  3. For programmatic navigation outside components, create a custom history instance
  4. Use the Navigate component for declarative redirects
  5. Migration requires updating all history usage to navigate

The new navigation API in v6 provides a more intuitive and flexible way to handle routing in your React applications. While it requires some changes from v5 patterns, the improvements in relative navigation and API consistency make it worth the effort to upgrade.

Leave a Reply

Your email address will not be published. Required fields are marked *