-
-
Notifications
You must be signed in to change notification settings - Fork 158
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Nuqs changes router.pathname
when the query param is changed with rewrite in middleware
#914
Comments
Thanks for the report, please note that If you are able to upgrade Next.js to 14.2.0, you should be able to use |
@franky47 Uhm, I'm sorry, I confused the numbers, we actually use "next": "^15.0.2". I updated the reproduction to use this next version. The behaviour is the same. I also tried update to nuqs 2, and the issue was the same |
For point n°2 (the tenant alias being added to the search params), I think this is due to how Next.js pages router stores dynamic routes internally. If you inspect the internal router state after typing in the search bar, you'll see that the The pages router adapter could probably use a better implementation, I'll try and reproduce your use-case in the e2e test environment and iterate on possibles fixes. |
Yes, you might be right about that. The router.pathname issue still stands though, I think it produces unexpected navigation to the index page on writing to input (but not always, I couldn't reproduce this in the example) |
While I was adding tests in #917, I found that using And to add to the confusion, some of the tests fail in dev but pass in prod 😓 |
Yes, but shallow: false doesn't make much sense in our case, we're using client rendering and notifying server is not what we wan't here. Maybe we can add it as a workaround to fix our current prod issue until this is fixed. But since it looks like this won't be an easy fix and it's causing serious instability, seems like we will have to move away from nuqs :/ |
Could you please show me how you updated search params with There may be something I'm missing, but calling the router methods with a rewritten path always ends up in an error, as the dynamic part of the route (the rewritten |
Ah wait I think I found the secret combination: router.replace(
{
pathname: router.pathname,
query: {
// Add the URL params here
tenant: 'david',
// AND the search params (if they don't conflict)
search: 'Hello, world!'
}
},
{
pathname: router.asPath,
query: {
// Add _all_ search params here, but not the URL params:
search: 'Hello, world!'
}
},
{ shallow: true }
) Now onto finding how to correctly extract only the URL params and merge them with the non-conflicting search params in the first query.. |
Yes, I came to more or less same conclusion, but I also needed to strip existing query params from This is my own implementation that accounts for the rewrite param: import { useEffect, useState, useMemo } from 'react';
import { useRouter } from 'next/router';
export type URLStateOptions<T> = {
defaultValue: T;
clearOnDefault?: boolean;
shallow?: boolean;
};
export const usePagesRouterURLState = <T extends string = string>(
key: string,
{ defaultValue, clearOnDefault, shallow = true }: URLStateOptions<T>,
): [T, (value: T) => void] => {
const router = useRouter();
const [value, setValue] = useState<T>(() => {
if (!router.isReady) {
return defaultValue;
}
return (router.query[key] as T) || defaultValue;
});
const queryValue = useMemo(() => router.query[key] as T, [router.query, key]);
// Sync from URL to state
useEffect(() => {
if (router.isReady) {
setValue(queryValue || defaultValue);
}
}, [router.isReady, queryValue, defaultValue]);
const updateValue = (newValue: T) => {
if (newValue === value) return;
setValue(newValue);
const currentQuery = { ...router.query };
if (clearOnDefault && newValue === defaultValue) {
delete currentQuery[key];
} else {
currentQuery[key] = String(newValue);
}
const url = {
pathname: router.pathname,
// Path query should include tenantAlias
query: currentQuery,
};
const asPath = {
// Remove query from asPath
pathname: router.asPath.split('?')[0],
// asPath query should not include tenantAlias
query: filterQuery(currentQuery, ['tenantalias']),
};
router.replace(url, asPath, { shallow });
};
return [value, updateValue];
};
type QueryValue = string | string[] | undefined;
const filterQuery = (
query: Record<string, QueryValue>,
excludeKeys: string[],
) => {
const filtered: Record<string, string> = {};
Object.entries(query).forEach(([key, value]) => {
if (!value || excludeKeys.includes(key.toLowerCase())) {
return;
}
if (Array.isArray(value)) {
filtered[key] = value[0];
} else {
filtered[key] = value;
}
});
return filtered;
}; |
Hah, I came to the same conclusion just before I saw your message 🙌 Here's a build that passes the repro test, let me know if it works for you:
I'll add some more tests to check for robustness (catch-all segments, push/replace, shallow true/false etc..). |
Thanks, but I'm running into issues when wrapping with Nuqs adapter in _app.tsx. I'm not using pnpm so not sure if that's a pnpm issue https://stackblitz.com/edit/sb1-kbhrcumz?file=pages%2F_app.tsx |
Great! In my app that seems to be working. However on stackblitz.com/edit/sb1-kbhrcumz?file=pages%2F_app.tsx it seems like the query is not updated in the URL at all? Not sure why is that |
That's because the rendered webpage runs in an iframe, so it's the iframe URL that gets updated: Thanks for your feedback and your patience! #917 should land today in |
Thank you for the efforts as well! |
🎉 This issue has been resolved in version 2.4.0 🎉 The release is available on: Your semantic-release bot 📦🚀 |
Context
What's your version of
nuqs
?What framework are you using?
Which version of your framework are you using?
(edited)
Description
We have a multitenant setup in our next js app and we use middleware to rewrite different hosts to path. So for example www.test.com will rewrite to www.ourapp.com/test. (see the simplified middleware in the example).
When we use nuqs, the pathname seems to change unexpectedly after nuqs does the URL manipulation. Altough there could be bug in our middleware as well, without nuqs, it works as expected. So I suspect that the issue is happening somehwere when nuqs does the manipulation with the URLs and it somehow clashes with our middleware rewrite
Reproduction
https://stackblitz.com/edit/sb1-zrnx1nia?file=pages%2F%5BtenantAlias%5D%2Fcontacts.tsx
Example: Steps to reproduce the behavior:
router.pathName
changes from '/[tenantAlias]/contacts' to '/[tenantAlias]'. Also in the middleware, we're seeingreq.nextUrl.href http://localhost:3000/contacts?search=p&tenantAlias=contacts
. Why is tenantAlias getting added to the query params?-->
The text was updated successfully, but these errors were encountered: