withRouter in Next.js – When and How to Use it?

Next.js is a popular React framework that enables us to build server-side rendered and statically generated web applications. One of the core features of Next js is client-side routing and navigation by using the <Link> component from next/link. [lwptoc] But in some cases, instead of navigating by using a <Link>, we need to navigate programmatically…

By.

•

min read

Next.js is a popular React framework that enables us to build server-side rendered and statically generated web applications. One of the core features of Next js is client-side routing and navigation by using the <Link> component from next/link.

[lwptoc]

withRouter in Next.js - When and How to use it?

But in some cases, instead of navigating by using a <Link>, we need to navigate programmatically in our application for example in a menu or sidebar navigation, on form submissions, pagination, or login/logout flows etc.

In such situations, we can use the withRouter higher-order components.

withRouter gives components access to the router prop so they can use imperative navigation methods like push() and replace().

 

When to Use withRouter

In Next.js, by default, only page components get access to the router prop automatically. Whereas Non-page components like headers, footers, and menus do not have routing capabilities. Following are some of the non-page components where we may use withRouter HOC:

  • Login and logout flows in a header or sidebar
  • Category filters that navigate to different product pages
  • Pagination navigation
  • Breadcrumb or multi-level navigation
  • Back/forward browser history buttons

withRouter allows us to easily add routing context to any component, which enables us to navigate imperatively like a page.

For using it, we wrap a component export with the withRouter higher-order component which give it access to history, location, match and other routing props.

import { withRouter } from 'next/router'

function MyComponent({ history }) {
  function handleLogin() {
    history.push('/login') 
  }
  
  return <button onClick={handleLogin}>Login</button>
}

export default withRouter(MyComponent)

This approach proves cleaner than passing down the router prop from every parent component just to enable routing in a child.

 

How withRouter Works

Under the hood, withRouter is a higher-order component (HOC) that takes a React Component as input and returns a Component having additional routing props.

It basically works by extracting the router object from the React context which is provided by Next.js and  _app.js file creates this context which wraps all pages.

The withRouter simply accesses this context internally and passes down the history, location, match and other props to the wrapped component as already mentioned. As a result, we get access to routing capabilities outside of <Link> and page components. We can do similar Router enablement to any component in our app.

 

How to Use withRouter?

We can start by importing the withRouter from ‘next/router’:

import { withRouter } from 'next/router'

Then we need to wrap the exported component with the withRouter HOC:

function MyComponent({ history }) {

  return <div>My Component</div>

}

export default withRouter(MyComponent)

Now MyComponent will receive the same props as a page component – history, location, match etc.

Thereafter, we can use the history prop to navigate in the app:

history.push('/new-page')

history.replace('/new-page')

The component will not become a page, but it can navigate like one.

 

Alternative to Link

We can easily deploy withRouter as an alternative to <Link> in cases where you need to navigate programmatically.

For example, in a sidebar navigation:

<Sidebar>
  <MenuItem onClick={() => history.push('/settings')}>Settings</MenuItem>
</Sidebar>

Or for a pagination component:

function Pagination() {
  const handleNext = () => {
    history.push(`/products?page=${nextPage}`)
  }
  // ...
}

export default withRouter(Pagination)

So, by using withRouter allows routing capabilities in components other than pages.

 

How to Access Route Params?

Now, let’s see how we can access route params directly from the other props added by withRouter:

function Nav() {
  const { pathname, query, asPath } = props;
  // ...
}
export default withRouter(Nav)

This will allow us to conditionally show elements based on the current route.

Moreover, withRouter keeps routing logic inside the wrapped component itself, instead of any need to pass callbacks down from parents which helps to decouple and isolate concerns.

 

Limitations for Using withRouter

The withRouter HOC has very useful features, but it also comes with a few limitations, which need to be discussed and kept in mind while using it:

  • When a parent re-renders, it can cause extra re-renders on the wrapped component which can cause extra load. So you can consider using React context if you need to avoid this.
  • Components become less reusable if they have routing logic embedded with withRouter.
  • We can still pass routing props from parents manually instead of using withRouter. So only use it when you need the convenience.

So we can say that withRouter is a useful tool for certain situations but also has drawbacks. It should be used after doing a quick maths on priorities for navigation components, and avoid its overuse.

Leave a Reply

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