next-safe-navigation
next-safe-navigation copied to clipboard
Suggestion: useSearchParamState
Sometimes it's useful to use the search params to store state. We currently have something like this:
const [query, setQuery] = useSearchParamState('query', z.string(), "defaultQuery");
Where setQuery actually changes the search params and updates the state. I'd love to incorporate this into the library. Any interest?
Thinking this look like:
export const { routes, useSafeParams, useSearchParamsState } = createNavigationConfig(
// ...
)
const [{ query, page }, setSearchParams] = useSearchParamsState('search');
Thanks for another great suggestion @iamnafets!
Could you elaborate a bit more over how would this be different/better than using:
export const { routes, useSafeParams, useSearchParamsState } = createNavigationConfig(defineRoute => ({
search: defineRoute('/search', { search: z.object({ query: z.string(), page: z.coerce.number() }) })
}));
// Search Page
export default function SeachPage() {
// ...
return (
<Pagination>
<Link href={routes.search({ search: { query, page: page + 1 } })}>Next page</Link>
</Pagination>
)
}
For SPAs, you often want to manipulate the querystring without navigating. React's Dispatch<SetActionState<T>> takes a lambda which passes the current value allowing you to do something like setSearchParams(old => ({ ...old, page: old.page +1 })) instead of re-assembling the whole object for if your queryString becomes large.
For SPAs, you often want to manipulate the querystring without navigating.
How come? I mean, what's the point of storing state in the URL if you're not navigating?
How come? I mean, what's the point of storing state in the URL if you're not navigating?
There are quite a few situations where you'd want to do this. We use it for query parameters for filtering a table. The general idea is that by having state reflected in the URL, you can make your URLs much more useful for sharing purposes. There's a great lib, nuqs (https://nuqs.47ng.com/), which I use extensively for this.
Actually, I came here to suggest considering integration with nuqs. It would be incredibly powerful to be able to define nuqs style query state for a route, and then use the hooks it provides for getting/setting searchParams, while keeping the validation checks provided by the current implementation.
There are quite a few situations where you'd want to do this. We use it for query parameters for filtering a table. The general idea is that by having state reflected in the URL, you can make your URLs much more useful for sharing purposes. There's a great lib, nuqs (https://nuqs.47ng.com/), which I use extensively for this.
Yes, I get the point of having state reflect in the URL but I strongly disagree that there are any situations where a query parameter changing doesn't reflect on browser navigation
Yes, I get the point of having state reflect in the URL but I strongly disagree that there are any situations where a query parameter changing doesn't reflect on browser navigation
Well, this is precisely how nextJS used to work: https://nextjs.org/docs/pages/building-your-application/routing/linking-and-navigating#shallow-routing
This is really a semantic issue. Changing the query does reflect on "browser navigation" - but only on first load. After that, updates can optionally be done "client first", so that you can use query parameters as direct replacements for useState. You then get the best of all worlds (deterministic initial state, and better UX when state changes).
I think one difference might be that a useSearchParamState could maintain the rest of the params. So for instance, if the current page has many query params, then changing only one would require something like this:
setSearchParams({ page: page + 1 });
vs
routes.search({
page: page + 1,
query,
sort
// etc
});
But I believe this could be built on top of this library.