70

I am developing a ecommerce store using NEXT.JS and Redux. So in product listing page, I have sorting select dropdown with Price Low to High, Price High to Low and New Arrivals. Upon selecting this option, I want to change the URL without page refresh and API call should occure. I have tried using below code, but it is not working and page is reloading.

function sortBy(value) {
    router.replace({
        pathname: '/products/'+slug,
        query: { sort: value }
    })

    dispatch(fetchproducts(slug, sort));
}

The above code just refresh the current page and appending sort param to URL.

So is it possible to do it without page refresh like in Flipkart.

5 Answers 5

116

With the help of shallow-routing change of URL without doing a page reload is possible. It can be enabled by passing explicit option object as third argument to Router.push, i.e { shallow: true }

From the docs

Shallow routing allows you to change the URL without running data fetching methods again, that includes getServerSideProps, getStaticProps, and getInitialProps.

You'll receive the updated pathname and the query via the router object (added by useRouter or withRouter), without losing state.

For example, this how you would update the query param sortBy for pathname /products with the help of shallow-routing.

Router.push({
  pathname: '/products',
  query: { sortBy: 'price' }
}, 
undefined, { shallow: true }
)

But there are a few caveats It is not possible to do shallow-routing between different pages, it works only for same page URL changes. See the caveat section for more details.

For example, you can update a query param for page /product page, but it won't be possible if you try to do shallow-routing from /product to /product/[slug] because they are two distinct pages.

// page will reload because shallow-routing not possible between the pages
Router.push('/product', '/product/some-product?sortBy=price', { shallow: true })
Sign up to request clarification or add additional context in comments.

8 Comments

I just want to add ?sort=3 to URL. Current URL is http://localhost:3000/products/dfhdf/sgsdg?sort=1. But still the page is reloading. I have used const router = useRouter().
Then you can use router.push. Pass the first argument and second argument as is and provide the third argument as on object with option shallow as true { shallow: true}. Remember it will only work same page URL changes.
router.push('/products/dfhdf?sort=1', '/products/dfhdf?sort=1', { shallow: true}). Not working, URL is same. Just added ?sort=1.
I suspect the dfhdf part is a route param for a dynamic route. And the page looks something like pages/products/[slug].js in file system. So you should be router.push should look something like this router.push('/products/[slug]?sort=1', '/products/dfhdf?sort=1', { shallow: true}
Yes. That did the trick. It is a dynamic route [...slug].js. Thanks for the response.
|
23

Example: you have a folder like: posts/[id].js and your url is like http://something.com/posts/123

You want to add a query param that will not refresh the page and your url will be like: http://something.com/posts/123?param=ok

all you need to do is:

const postId = 123;
const param = 'ok';
router.push(
    {
      pathname: `/posts/[id]`,
      query: {
        postId,
        param
      }
    },
    `/posts/${postId}?param=${param}`,
    {shallow: true}
);

Comments

5

This worked for me. It's easier than useRouter but fewer options. Gives me an anchor link which is what I needed. Read more in the NextJS docs

My [category].js has a fetch call in a useEffect hook, and router picks up the URL parameters, makes the call, and populates the data. The page doesn't refresh.

function createSortLink(sortBy) {

    const url = new URL('https://example.com/products/[category].js');
    url.searchParams.set('sortBy', sortBy);

    return (
        <Link 
          href={url}
          shallow={true}
          >
          {name}
        </Link>
        }
    )
}

2 Comments

Can you explain how do you set searchParams field on a string? I dont get how it works
@ColdDarkness Good point. It needs to be a URL object. I updated my answer. Thank you.
1

for anyone using appRouter (next.js 13+), use window.history.replaceState instead.

from the docs:

Next.js allows you to use the native window.history.pushState and window.history.replaceState methods to update the browser's history stack without reloading the page.

window.history.replaceState({}, '', `/products?sort=xxx`)

Comments

-1

for guys who uses next.js 14 or 13 all you need is add scroll param to you code like this

router.push('/your route' + '?' + 'your query', {scroll : false})

1 Comment

Thank you! This solved it for me. For some reason, shallow: true didn't help, pages would always jump to top on params (filters in URL) change, perhaps because we have a lot of middleware for multilingual URLs... but scroll arg fixed it

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.