Open Tomekmularczyk opened 1 year ago
Sorry if that is not a bug but a feature request. Seems like this is a very common use case that is missing from the new NEXTjs or is now any other way to achieve what I want?
@Tomekmularczyk try to use history.replaceState(null, "", url);
shallow
is a feature present in the Pages Router. To be honest i believe will be difficult to create some features without it for App Router.
Probably one good way to communicate between server and client components is query parameters using shallow. without the prevention of not calling the server again makes this approach impossible
@Tomekmularczyk try to use history.replaceState(null, "", url);
Thanks for this tip! While it helps a lot with performance (not triggering a cascade of requests), I found there's a lack of sync between the history state and Next's router, meaning that clicking Links and using the imperative router.replace
methods won't always trigger a page render.
My use-case here is bringing app router support for next-usequerystate
. The initial implementation (going through the router) ended up triggering a lot of network requests and blocking the UI (see discussion). Switching to the history API helps a lot with performance, but brings all kinds of sync issues with normal Next.js routing.
Edit: next-usequerystate
now supports shallow updates of search params, and all issues above have been resolved. Check it out!
Just to let anyone finding this topic know that there is a more comprehensive discussion on this issue here #48110 where the Devs are saying a solution is on the roadmap....
For anyone experiencing similar issue, I've also used @izica solution for pure client-side navigation. I have a case where I also need to watch the query params client-side. And to make it work I've created this custom hook:
import {useState, useEffect, useCallback} from 'react';
import {usePathname, useSearchParams} from "next/navigation";
function patchHistory(history: History){
if ((history as any)['patched']) {
return;
}
const pushState = history.pushState;
const replaceState = history.replaceState;
history.pushState = function(state) {
pushState.apply(history, arguments as any);
window.dispatchEvent(new Event('pushstate'));
};
history.replaceState = function(state) {
replaceState.apply(history, arguments as any);
window.dispatchEvent(new Event('replacestate'));
};
(history as any)['patched'] = true;
}
export function useCurrentUrl(): URL | null {
// Helper function to get the current URL
const pathname = usePathname();
const query = useSearchParams();
const [currentUrl, setCurrentUrl] = useState<string | null>(
typeof window === "undefined" ? null : window.location?.href
);
const handleUrlChange = useCallback(() => {
setCurrentUrl(window.location.href);
}, []);
useEffect(() => {
if (typeof window === "undefined") {
return;
}
handleUrlChange();
patchHistory(window.history);
// Add event listener for URL changes
window.addEventListener('popstate', handleUrlChange);
window.addEventListener('pushstate', handleUrlChange); // Custom event for pushState
window.addEventListener('replacestate', handleUrlChange); // Custom event for replaceState
// Clean up the event listener on component unmount
return () => {
window.removeEventListener('popstate', handleUrlChange);
window.removeEventListener('pushstate', handleUrlChange);
window.removeEventListener('replacestate', handleUrlChange);
};
}, []);
if (!currentUrl) {
// just use your hostname instead of process.env.VERCEL_URL
return new URL(`https://${process.env.VERCEL_URL}${pathname}?${query.toString()}`);
}
return new URL(currentUrl);
}
Hope we'll get the official solution soon. Nextjs 14.0.3 - still same issue.
Verify canary release
Provide environment information
Which area(s) of Next.js are affected? (leave empty if unsure)
App directory (appDir: true), Routing (next/router, next/navigation, next/link)
Link to the code that reproduces this issue
https://github.com/Tomekmularczyk/next-shallow-routing
To Reproduce
The app has 3 links that change the searchParam to one of:
/?step=1
,/?step=2
or/?step=3
. Notice that initially when you click on the link and change the search param, the server code reruns and causes the all the data fetching logic to rerun. Once the link has been visited at least once, you can navigate without causing any server code to run again (thanks to in-memory client-side cache). See the video:https://github.com/vercel/next.js/assets/12544704/14220251-c551-452a-b39a-f16e8853018a
Describe the Bug
Updating search params causes all the data on the server to be refetched when it's often a case where search params are used only to store some meta data or UI state.
Expected Behavior
I want to update the URL with a search param without rerunning the server code and triggering data fetching all over again. This used to be something called a shallow routing in the previous versions of NEXT.
Which browser are you using? (if relevant)
No response
How are you deploying your application? (if relevant)
Vercel
Related discussion https://github.com/vercel/next.js/discussions/48110#discussioncomment-5862857