32

I am using router from next by importing useRouter from next/router.

I am trying to find a solution which will not scroll to the top of the page when I change the query of the URL. Is there any solution? I know that Link component from Next has that option, but I need to use Router component. My next version is 10.0.5.

const router = useRouter();

const changeCurrency = (newCurrency) => {
   //Do some stuff here

    Router.push({
        pathname: router.pathname,
        query: { ...router.query, currency: newCurrency.value },
    });
};
anticol
  • 487
  • 1
  • 4
  • 12
  • 1
    One thing I can think of is listen to the routeChangeStart event and preserving the window position there and then scrolling to it when routeChangeComplete fires. https://nextjs.org/docs/api-reference/next/router#routerevents – Gh05d Jan 26 '21 at 14:03
  • 1
    @Gh05d Yes, I was thinking about that but not sure how to preserve the window position. – anticol Jan 26 '21 at 14:14
  • 1
    You could save it to the state when the routeChangeStart event fires. – Gh05d Jan 26 '21 at 14:27

3 Answers3

68

router.push has a scroll option, it is true by default. You can turn it off like this:

const router = useRouter();

async function navigate(newCurrency) {
  router.push({
    pathname: router.pathname,
    query: { ...router.query, currency: newCurrency.value },
  }, undefined, { scroll: false });
}

router.push accepts the most of (if not all) next/link's props in the options object. You can check them here: https://nextjs.org/docs/api-reference/next/link

Gokhan Sari
  • 7,185
  • 5
  • 34
  • 32
12

if you like to use router.push directly with given destination path including the query values ,

and preventing scroll to top, you can use also :

router.push(`/?page=2`, undefined, { scroll: false });

this is just example , and change it based on you case/ requirements.

i hope the helpful

K.A
  • 1,399
  • 12
  • 24
-2

A weird workaround from me. Just get the particular component in the view. Here's how.

import React, { useEffect, useRef } from 'react';


function MyAccount() {
  const containerRef = useRef(null);

  useEffect(() => {
    setTimeout(() => {
      containerRef.current.scrollIntoView({ behavior: 'smooth' });
    }, 250);
  }, []);

  return (
    <div ref={containerRef}>
   {/* It will be your particular component that needs to be shown  */}
        <UserInformation /> 
    </div>
  );
}

export default MyAccount;

Some people may find it useful! That's why I posted this here. scroll=false is the best solution if you want to retain view.

Md Fazlul Karim
  • 355
  • 7
  • 15
  • 1
    Adding timeouts for focus management is usually a bad practice since it can break in different scenarios. For example, on slower networks or if the main thread is busy, your component could take longer than 250ms to mount and the logic there would not work. – Adarsh Konchady Aug 02 '21 at 22:33
  • Yes, it's true. It's a tradeoff. Is there any better alternative without incurring performance penalty in this particular scenario? The accepted answer doesn't work in some scenario. I've faced it in production. It's a known issue when I wrote that answer. It was my workaround. Thank you in advance. – Md Fazlul Karim Aug 03 '21 at 06:58
  • Thanks for that info. Do you know which scenarios did the accepted solution not work for you though? Wonder if there was some component unmounting causing container heights to go 0 which was causing scroll to top behavior. Can't comment without knowing the details but feel free to tag the NextJS issue if it's logged on their repo. – Adarsh Konchady Aug 03 '21 at 14:34
  • 1
    The issue is fixed, but still problematic in some mobile browsers. Actually, I have given this answer in that issue too. I just copied it here. I use react-device-detect to render my sites. For mobile browsers I use this and for desktop browsers I use the normal way. As the frontend is pretty much lightweight, there is a pretty low chance of happening that. Besides, it's not a mission critical logic. If the logic is not honored, no problem from my part. Hope it will be fixed in coming versions soon. – Md Fazlul Karim Aug 03 '21 at 18:28