Reputation: 2286
I created a filter that when I clicked confirmed button changes url.
For example, When I clicked page 1 and place type guesthouse in paris, url looks like this below.
http://localhost3000/findstay?page=1&per=10&place_type=guest_house&city=paris
Now I want to changed the result when url changed. Suppose when I manually changed query params like below, filter should also changed.
http://localhost3000/findstay?page=1&per=10&place_type=hotel&city=newYork
In order to do this. I created a file name findstay in pages folder and created findstay-filter component inside of components folder.
import React from "react";
import FindstayFilter from "@/components/findstay/findstay-filter";
interface IFindstayProps { };
const Findstay: React.FC<IFindstayProps> = () => {
return <FindstayFilter />;
};
export default Findstay;
All the logic I have explained are written inside of FindstayFilter component.
And this is the code that pushses url when FindstayFilter is rendered.
useEffect(() => {
const { city, page, per, placeType } = query;
const _page = parseInt(page || 1 as any);
const _city = city || state.cityState; // paris
const _placeType = placeType || "";
router.push({
pathname: `/findstay`,
query: {
page: _page,
per: 10,
plage_type: _placeType,
city: _city,
}
}, undefined,
{ shallow: true })
const initialRender = {
page: _page,
placeType: _placeType,
city: _city,
}
searchAvailableBookingDays(initialRender).then(res => res.json().then(value => setData(value)));
}, []);
As you can see I used {shallow: true} option and url does not changes only query params are changed. However when I changed one of queries manually (city=paris -> city=newYork), component re-renders and reset query params that I pushes when component renders first time.
Why shallow option is not working?
Upvotes: 11
Views: 10560
Reputation: 124
You are likely seeing re-renders caused by state changes caused by useRouter
's state changing due to the "new" route.
An easy fix for this is to use Router
instead of useRouter
. Both function the same as useRouter
is just a RouterContext
to the Class:
useRouter: https://github.com/vercel/next.js/blob/canary/packages/next/client/router.ts#L127-L129
Router: https://github.com/vercel/next.js/blob/canary/packages/next/next-server/lib/router/router.ts#L505
Be aware that you'll need to change the parent components in your component tree to also use Router
instead of useRouter
.
Upvotes: 0
Reputation: 1318
The shallow
option is working. Its goal is to not let your browser navigate away. But it definitely triggers a state update, which triggers the re-render.
Surely, you've had occasions where you really need it to trigger that state update so you can use updated query param values.
Now, how do you update the URL without triggering a re-render? You use window.history
, not Next router.
So, instead of this:
router.push({
pathname: `/findstay`,
query: {
page: _page,
per: 10,
plage_type: _placeType,
city: _city,
}
}, undefined,
{ shallow: true })
You would do this:
const newUrl = `/findstay?page=${_page}&per=10&place_type=_placeType&city=_city`
window.history.replaceState({ ...window.history.state, as: newUrl, url: newUrl }, '', newUrl)
It's ugly, but it works as expected. A really nice way to keep your route synced with your state.
I'd recommend you turn it into a utility function.
Upvotes: 11