Fix reload loop from redundant URL sync on mount

useQueryFilter called router.replace on every mount even when the query
was unchanged. On the static host that emitted a non-trailing-slash URL,
which 301-redirects back, and Next treats the redirect as a hard
navigation and remounts — firing the effect again in an endless reload
loop. Skip router.replace when the computed query equals the current
one.
This commit is contained in:
cc
2026-06-03 19:49:22 +02:00
parent fdc454b798
commit 696f75a1fb
+10 -2
View File
@@ -23,20 +23,28 @@ export function useQueryFilter(param = "q", delay = 300) {
const [debouncedKeyword] = useDebounce(keyword, delay);
useEffect(() => {
const next = new URLSearchParams(params.toString());
const current = params.toString();
const next = new URLSearchParams(current);
if (debouncedKeyword) {
next.set(param, debouncedKeyword);
} else {
next.delete(param);
}
// Nothing changed — don't touch the URL. A redundant router.replace on
// mount triggers a host trailing-slash redirect, which Next treats as a
// hard navigation and remounts us, firing this effect again in a loop.
const query = next.toString();
if (query === current) {
return;
}
// usePathname() may include the configured basePath, which router.replace
// re-applies — strip it to avoid doubling (mirrors version-switcher).
const path =
basePath && pathname.startsWith(basePath)
? pathname.slice(basePath.length)
: pathname;
const query = next.toString();
router.replace(query ? `${path}?${query}` : path, { scroll: false });
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [debouncedKeyword]);