20

Is there a way to execute a Router.push() without reloading the page using Next.js?

I am using a [...all].js main file for a page that based on the url renders different components, but i want to be able to move between them without triggering a full page reload - it is a multi-step form.

In other words, I want to be able to move between the steps of the form by also updating the URL from 'form/1' to 'form/2'

Francesco S
  • 2,125
  • 4
  • 15
  • 16

4 Answers4

30

Set option shallow to true to avoid page refresh

router.push('/?step=2', null, { shallow: true })
MWO
  • 2,627
  • 2
  • 10
  • 25
naijab.com
  • 508
  • 6
  • 10
  • @FrancescoS Please set to answer. Thanks – naijab.com May 01 '20 at 18:32
  • 9
    Using null in `router.push('/?step=2', null, { shallow: true })` may lead to TypeError: Cannot read property 'auth' of null. It's better to use undefined. `router.push('/?step=2', undefined, { shallow: true })` – Aga Aug 02 '21 at 12:26
  • Note that this probably only relevant if your page uses `getStaticProps`, `getServerSideProps` or `getInitialProps`. – Garrett Sep 11 '22 at 20:45
  • For anyone looking the documentation: https://nextjs.org/docs/routing/shallow-routing shallow mitigated the flickering UI caused by reload for me. – Ville Apr 10 '23 at 20:47
5

This page comes first on Next.js and 'page reloads'. To save others some time troubleshooting, consider this code:

router.push({query: {page: 1}}, undefined, { shallow: true });

It would seem there are some configurations of Next.JS that would make the page reload even if the query is the same as before, which is an easy way towards an infinite cycle of page reloads. Moreover, the browser would also reload unless you explicitly specify the pathname. I see this behavior on my server, but not on my laptop, both of which run Next.js 10.1.3. As far as I can tell, the only difference is there is no base URL set on my laptop, while the server does have a base URL. This remedies the problem:

let routerOpts = {page: 1};
if (!_.isEqual(routerOpts, router.query)) 
  router.push({pathname: router.pathname, query: routerOpts}, undefined, { shallow: true });

As far as I can tell, 'shallow' makes no difference and this works fine as well:

let routerOpts = {page: 1};
if (!_.isEqual(routerOpts, router.query)) router.push({pathname: router.pathname, query: routerOpts})
Maksym
  • 1,430
  • 1
  • 11
  • 13
0

This page has more on router

router.push(url, as, options)

url - The URL to navigate to

as - Optional decorator for the URL that will be shown in the browser. Before Next.js 9.5.3 this was used for dynamic routes, check our previous docs to see how it worked

options - Optional object with the following configuration options:

shallow: Update the path of the current page without rerunning getStaticProps, getServerSideProps or getInitialProps. Defaults to false

You don't need to use router.push for external URLs. window.location is better suited for those cases

Chukwuemeka Maduekwe
  • 6,687
  • 5
  • 44
  • 67
0

I also encounted the above issue, where actually adding {shallow: true} was not good a enough solution.

Depending on the events you have on your form input elements such as: onKeyUp upon hitting the enter key, for example, You may also need to call event.preventDefault() to keep the form from reloading the page and allow router.push() to do it's thing. Yeah, D'oh! ;}

const search = (e) => {
   if ( event.key === 'Enter' && event.target.value) {
      event.preventDefault();
      router.push(`/foo?q=${event.target.value}`, undefined, { shallow: true })
   }
}

return(
  <input 
    ... 
    onKeyPress={search} 
  />
)

grantmx
  • 106
  • 9