47ng/nuqs

State is not resetting on page change

zbeyens opened this issue ยท 6 comments

Context

What's your version of nuqs?

"nuqs": "^1.17.1",

Next.js information (obtained by running next info):

Operating System:
  Platform: darwin
  Arch: arm64
  Version: Darwin Kernel Version 23.4.0: Fri Mar 15 00:12:49 PDT 2024; root:xnu-10063.101.17~1/RELEASE_ARM64_T6020
Binaries:
  Node: 20.12.1
  npm: 10.5.0
  Yarn: 1.22.19
  pnpm: 8.15.6
Relevant Packages:
  next: 14.1.4
  eslint-config-next: 14.1.4
  react: 18.2.0
  react-dom: 18.2.0
  typescript: 5.4.5
Next.js Config:
  output: N/A

Are you using:

  • โœ… The app router

Description

On page change to a route without search params, useQueryStates value is not resetting but useSearchParams is correctly doing so.

Here is my workaround:

  const searchParams = useSearchParams();
  const queryState = Object.fromEntries(searchParams.entries());
  queryState.pageIndex = queryState.pageIndex ?? 0;
  queryState.pageSize = queryState.pageSize ?? defaultPageSize;
  queryState.sort = queryState.sort ?? defaultSort;

  const [, setQueryState] = useQueryStates(
    {
      pageIndex: parseAsInteger.withDefault(0),
      pageSize: parseAsInteger.withDefault(defaultPageSize),
      sort: parseAsString.withDefault(defaultSort),
    }
  );

Is there a way to get the same value than useSearchParams?

Do you have a reproductible example?

Here it is https://github.com/zbeyens/shadcn-table/tree/nuqs

You can click on "Variant" in the header to switch page to /variant, where I would expect sort=title.asc to be set as search param, which is the case on page refresh.

2024-04-18.at.15.40.48.mp4

From what I can see in your example:

  1. The /variant page uses the same useQueryStates hook, but with a different default value for the sort key (createdAt.desc on /, title.asc on /variant).
  2. When navigating to the /variant page, there is a series of effects that adds the search params back to the URL.

There is a weird behaviour to understand about Next.js client side navigation between pages: it will render the destination page in the background before updating the URL and swapping the component trees. When that background rendering is done, it is done with the current URL (the one that you were on before clicking the <Link>). There have been issues reported with this in #524 (comment).

Now what happens in this case is the following:

  1. You click the link to navigate to /variant
  2. The destination page component renders, but with the populated URL query string sort=createdAt.desc
  3. The useQueryStates hook in useDataTable is initialised with this value
  4. Next.js changes the URL to /variant and starts running effects
  5. Those effects now ignore the new default value, as there is already a state in place, so it syncs that state back into the URL.

Note: commenting out the useEffect that reads the sorting object and updates the search params solves the issue, at the expense of not having the sort option explicitly reflected in the URL. This might help you figure out another way to sync that particular piece of state.

Now I do agree that this all feels like a bug, unfortunately nuqs doesn't have a way to know the destination URL when a page transition occurs, since the rendering of the destination page is done ahead of time by Next.js. I'll create a simpler reproduction case for this behaviour and will report it to the Next.js team.

Thanks for detailed answer. That makes sense. If I understand correctly, nuqs can't reset the state on page transition since the destination URL (and its search params) are unknown. Perhaps having an option to reset the query state on page transition would be nice so it can pick the new defaults on the next page mount.

Actually there was a bug in the hook initialisation code, which used the URL location.search (which is not yet updated when mounting the destination page) rather than useSearchParams, which contains the correct destination search params.

I was afraid a fix would break compatibility with older versions of Next.js, but it looks like CI is all green (see #544).

Could you try 1.17.2-beta.1 and see if it fixes the issue on your end please? I tried it on a clone of your reproduction repo and it correctly switches to sort=title.asc when navigating to /variant.

๐ŸŽ‰ This issue has been resolved in version 1.17.2 ๐ŸŽ‰

The release is available on:

Your semantic-release bot ๐Ÿ“ฆ๐Ÿš€