Skip to content
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

return null for conditional component after setting value and need to trigger twice in order to work #359

Closed
jebie opened this issue Oct 4, 2023 · 4 comments · Fixed by #360
Labels

Comments

@jebie
Copy link

jebie commented Oct 4, 2023

Screen.Recording.2023-10-04.at.1.31.16.PM.mov

Here's the full code:

"use client";
import { parseAsString, parseAsStringEnum, useQueryState } from "next-usequerystate";

const Component1 = () => {
  const [param] = useQueryState("param", parseAsString);

  return param ? param : "null";
};

const Component2 = () => {
  const [param] = useQueryState("param", parseAsString);
  return param ? param : "null";
};

enum TargetComponent {
  Comp1 = "comp1",
  Comp2 = "comp2",
}

export default function Home() {
  const [_param, setParam] = useQueryState("param", parseAsString);
  const [component, seComponent] = useQueryState("component", parseAsStringEnum(Object.values(TargetComponent)));
  return (
    <div>
      <div className="p-5 border">
        {component === TargetComponent.Comp1 ? <Component1 /> : null}
        {component === TargetComponent.Comp2 ? <Component2 /> : null}
      </div>

      <div className="flex gap-2">
        <button
          onClick={() => {
            setParam("Component1");
            seComponent(TargetComponent.Comp1);
          }}
          className="border p-2"
        >
          Component 1
        </button>
        <button
          onClick={() => {
            console.log("aaa");
            setParam("Component2");
            seComponent(TargetComponent.Comp2);
          }}
          className="border p-2"
        >
          Component 2
        </button>
      </div>
    </div>
  );
}

In this scenario, in the first click of the button, the param value is null unless you need to re-click again the button, that is the time that param got a value.

@franky47 franky47 added the bug Something isn't working label Oct 4, 2023
@franky47
Copy link
Member

franky47 commented Oct 4, 2023

Thanks, this is definitely a bug. Looks like it's due to the combination of a few things:

  1. The deferred URL update queue
  2. The synchronous state sync across hooks
  3. The fact that we don't trigger re-render when history updates are coming from within the library

In your case, this means that:

  1. When clicking the button, the Home hooks have their state updated instantly, and the updated params queued for a deferred update (setTimeout(0))
  2. At the next tick, React re-renders the Home component with the correct values for both keys, and renders the corresponding child Component.
  3. When rendering this child Component, it reads its state from the URL, but which hasn't been updated yet (it will happen at the end of the current event loop tick)
  4. The URL is updated, and we see the history.replaceState call, but since it comes from within the library, there isn't a need to sync from an external navigation
  5. The child Component is not re-rendered, leaving it in the initial "null" state, or lagging behind when clicking the other button

As to how to fix this: the root of the issue seems to be that the child Component mounted immediately after a state update doesn't read its initial state correctly. Fixing this issue at the source seems like a better option than forcing re-renders for every history update (internal or external).

See PR #360 for a potential fix, I'll push a beta for you to try later today.

@github-actions
Copy link

github-actions bot commented Oct 4, 2023

🎉 This issue has been resolved in version 1.8.2-beta.1 🎉

The release is available on:

Your semantic-release bot 📦🚀

@jebie
Copy link
Author

jebie commented Oct 4, 2023

Thanks. It's now working on my end.

@github-actions
Copy link

github-actions bot commented Oct 4, 2023

🎉 This issue has been resolved in version 1.8.2 🎉

The release is available on:

Your semantic-release bot 📦🚀

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

Successfully merging a pull request may close this issue.

2 participants