Published on

How to Programmatically Navigate Using React Router

Authors
  • Name
    Ripal & Zalak
    Twitter

Introduction

In React Router, navigation is commonly handled using the <Link> component. However, there are situations where programmatic navigation is required, such as navigating based on a user action like a button click or a dropdown selection. This blog explores the modern and legacy approaches to programmatically navigate using React Router.


React Router v6: Using useNavigate

React Router v6 introduced the useNavigate hook, which replaces the deprecated useHistory hook. This hook provides a simple way to programmatically navigate within your application.

Example

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

function HomeButton() {
  const navigate = useNavigate()

  function handleClick() {
    navigate('/home')
  }

  return (
    <button type="button" onClick={handleClick}>
      Go Home
    </button>
  )
}

Key Features of useNavigate:

  • Accepts a path to navigate to.
  • Allows options like replace: true to replace the current history entry instead of adding a new one.

Advanced Example with State

You can pass state along with navigation:

navigate('/profile', { state: { userId: 123 } })

To access this state in the target component:

import { useLocation } from 'react-router-dom'

function ProfilePage() {
  const location = useLocation()
  console.log(location.state.userId)
}

React Router v5: Using useHistory

For applications using React Router v5, the useHistory hook is used for programmatic navigation.

Example

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

function HomeButton() {
  const history = useHistory()

  function handleClick() {
    history.push('/home')
  }

  return (
    <button type="button" onClick={handleClick}>
      Go Home
    </button>
  )
}

Differences Between useNavigate and useHistory

While useHistory works similarly to useNavigate, it is now deprecated in favor of the cleaner and more feature-rich useNavigate.


Legacy Approaches in React Router v4

1. Using withRouter

The withRouter higher-order component provides access to the history object as a prop.

import { withRouter } from 'react-router-dom'

const Button = withRouter(({ history }) => (
  <button type="button" onClick={() => history.push('/new-location')}>
    Click Me
  </button>
))

2. Using <Route> Component

You can render a pathless <Route> to always match the current location and use the history prop it provides.

import { Route } from 'react-router-dom'

const Button = () => (
  <Route
    render={({ history }) => (
      <button type="button" onClick={() => history.push('/new-location')}>
        Click Me
      </button>
    )}
  />
)

In earlier versions of React Router, the context API could be used to access the history object. However, this approach is not recommended as it tightly couples components to React Router’s implementation.

Example

class Button extends React.Component {
  static contextTypes = {
    history: PropTypes.shape({
      push: PropTypes.func.isRequired,
    }),
  }

  render() {
    return (
      <button type="button" onClick={() => this.context.history.push('/new-location')}>
        Click Me
      </button>
    )
  }
}

Best Practices for Programmatic Navigation

  1. Use Hooks for Modern React Projects: Prefer useNavigate for React Router v6 or useHistory for v5.
  2. Avoid Legacy Approaches: Context-based navigation and mixins are outdated and should be avoided.
  3. Centralize Navigation Logic: For complex apps, consider creating a reusable navigation utility or service.
  4. Ensure Accessibility: Always ensure navigation methods maintain accessibility standards, such as using buttons for click actions.

Conclusion

Programmatic navigation in React Router has evolved significantly over time. With the modern useNavigate hook, navigating programmatically has become cleaner and more intuitive. By understanding these approaches and best practices, you can effectively handle navigation in any React Router version.