47ng / nuqs

Type-safe search params state manager for React frameworks - Like useState, but stored in the URL query string.
https://nuqs.47ng.com
MIT License
4.82k stars 104 forks source link

`useQueryState` getter cannot access data on each render #404

Closed tordans closed 6 days ago

tordans commented 1 year ago

(This issue was https://github.com/47ng/next-usequerystate/issues/400 first, but that ticket is now about something else, so to keep related things together I moved it here.)

Context

What's your version of next-usequerystate?

    "next-usequerystate": "1.12.0",

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

FYI, I am stuck on this NextJS version due to https://github.com/blitz-js/blitz/issues/4253.

% npx next info

Operating System:
  Platform: darwin
  Arch: arm64
  Version: Darwin Kernel Version 22.6.0: Fri Sep 15 13:41:30 PDT 2023; root:xnu-8796.141.3.700.8~1/RELEASE_ARM64_T8103
Binaries:
  Node: 19.2.0
  npm: 8.19.3
  Yarn: N/A
  pnpm: 8.7.6
Relevant Packages:
  next: 13.5.6
  eslint-config-next: 13.5.6
  react: 18.2.0
  react-dom: 18.2.0
  typescript: 5.2.2
Next.js Config:
  output: N/A

Are you using:

Description

My issue is, that the useQuery getters dos not work on every render.

One thing that might be special about this app is, that I initialize the Page in https://github.com/FixMyBerlin/atlas-app/blob/develop/src/app/regionen/%5BregionSlug%5D/_components/MapInterfaceInitialization.tsx#L36-L51 manually. I cannot use .withDefaults for this (or I don't know how…) because I need the current URL state to call initializeMapRegionConfig for same very rough URL migration (see https://github.com/47ng/next-usequerystate/discussions/399 on this topic).

Reproduction

Video Here is a video which shows the issue in action https://we.tl/t-3JBSbIevOt

Steps

  1. Restart the dev server npm run dev; it only happens reliably on a fresh start (but did not look into this further, yet)
  2. Open https://staging.radverkehrsatlas.de/regionen/berlin
  3. The app starts with initialized=false and correctly sets the states setMapParam and setConfigParam
  4. However, in the following render, the getter for both return undefined ## MapInterfaceInitialization rendered {freshConfig: Array(5), urlConfigParam: null, initialized: true, mapParam: null, region: {…}} In this log, urlConfigParam and mapParam where just successfully set (or maybe just enqueued?) but are not present.
  5. I then get ## SelectThemes rendered (5) [{…}, {…}, {…}, {…}, {…}] which is correct because it is able to get the url state
  6. Then a lot of logging happens…
  7. And next time ## SelectThemes rendered null the same SelectTheme component is not able to get the url state. The URL itself still holds the state, though, it is just not able to read it.
  8. There are a few renders of ## MapInterfaceInitialization rendered {freshConfig: Array(5), urlConfigParam: null, initialized: true, mapParam: null, region: {…}} afterwards which still show null for the urlConfigParam

(Sorry for the wrong initial title, it was a stale text in the form…)

tordans commented 1 year ago

After François' initial feedback in https://github.com/47ng/next-usequerystate/issues/400#issuecomment-1813963582 I looked into a simpler setup, but the issue still persists:

The new code

https://github.com/FixMyBerlin/atlas-app/pull/51/files/d79dfe61055979e01316749eab067e6a67199956..d5bb3535e4ce54f17f354f833330e1dd8a6a583c

Reproduction

  1. Since I am using the regular .withDefaults now, the first renders are fewer and simpler, now
  2. I am getting ## MapInterface rendered {zoom: 11.8, lat: 52.507, lng: 13.367} (5) [{…}, {…}, {…}, {…}, {…}] which is what I expect
  3. But shortly after, I am the data for mapConfig is lost again ## SelectThemes rendered [] (see the empty [])
tordans commented 1 year ago

Follow up to https://github.com/47ng/next-usequerystate/issues/404#issuecomment-1816065673

It looks like I am making wrong assumption…

(a) Either about how .withDefaults works: I assumed that the input for withDefaults is only used and needed whenever the given queryparam is empty at the time. Because if it is present, that that will be used and withDefaults hat no effect, right?

However, looking at my current testing at https://github.com/FixMyBerlin/atlas-app/pull/51/commits/b5642dc3329e9033854d28d41bac76460f1c955b#diff-94a946c527a273e63467a5e6ced5fc9f38f159ef0bddff1fafc349ceab225875R5 where I provide the defaults as an optional param it appears as if the []

(b) And/or about how the getters are internally recognized as "being the same getter". I assumed that this is done just by the params, so regardless of the settings I provide, every time I use useQueryState('config',…) I would get the same internal store back. However, that is not correct, is it?

I now got it working in https://github.com/FixMyBerlin/atlas-app/pull/51/commits/c37c2d6e55f66105309d440a8a84a13afa320d2a where I made sure that all places of the code call the useQueryState exactly the same way. This is wasteful in my case, because the DB query to look for the initial data is only used on the first render when no state is present, yet.


With this working solution in https://github.com/FixMyBerlin/atlas-app/pull/51/commits/c37c2d6e55f66105309d440a8a84a13afa320d2a have have a few issues that are not ideal…

  1. I only want to query the DB when no state is present (the useRegion() hook)
  2. I want the URL to initialize with query params right away. Right now, the params only show up once I change stuff that is relevant to the params, but I want the to be visible right a on the second render — Update: I created https://github.com/47ng/next-usequerystate/issues/405 to discuss this
  3. I want the defaults to be derived from the possible initial URL state – which is what https://github.com/47ng/next-usequerystate/discussions/399 is about
Talent30 commented 1 year ago

Could you provide a minimal reproducible example in codesandbox please? I try to follow what you are saying but I am lost in the end...I am not a maintainer of this repo but I probability wouldn't want to go through the entire code base to figure out the bug

franky47 commented 6 days ago

Closing this as it might be out of date? Feel free to reopen if still relevant @tordans.