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

[Bug]: useNavigate does not work when wrapped in async fn, and the context that wraps the router changes #11240

Open
nonameprogram opened this issue Jan 31, 2024 · 1 comment
Labels

Comments

@nonameprogram
Copy link

nonameprogram commented Jan 31, 2024

What version of React Router are you using?

6.21.3

Steps to Reproduce

Based on the provided reproduction, when i click on the "User" link, it goes through Layout and User components. User changes state in context (which wraps the whole router) and it breaks the behaviour of navigate in Layout which is called 1s after rendering (it doesn't do anything).

https://codesandbox.io/p/devbox/6q36k2 (contains below fragment of code)

...

export default function App() {
  const [state, setState] = useState(false);

  return (
    <Ctx.Provider value={{ state, setState }}>
      <Router />
    </Ctx.Provider>
  );
}

const Layout = () => {
  const navigate = useNavigate();
  const { id } = useParams();

  useEffect(() => {
    (async () => {
      await new Promise((resolve) => setTimeout(resolve, 1000));
      // only url changes
      navigate(`/users/${id}/other`);
    })();
  }, []);

  return <Outlet />;
};

const User = () => {
  const { setState } = useContext(Ctx);

  useEffect(() => {
    // this is called before `navigate` in `Layout`
    setState(true);
  }, []);

  return <>User</>;
};
...

When i comment setState or assign navigate to useRef everything works correctly.

Expected Behavior

After clicking on the link and waiting 1s, the route /users/${id}/other should render correctly.

Actual Behavior

After clicking on the link and waiting 1s, the url changes to /users/${id}/other but I still see /users/${id}.

@tmak-ec
Copy link

tmak-ec commented Feb 22, 2024

We encountered a similar problem today.

Our case might be different from yours, because we only encounter such problem when reloading the page.
Turns out there is an check in the library that the navigate cannot be used until the history listener is being wired up.

(to: To | number, options: NavigateOptions = {}) => {
warning(activeRef.current, navigateEffectWarning);
// Short circuit here since if this happens on first render the navigate
// is useless because we haven't wired up our history listener yet
if (!activeRef.current) return;
if (typeof to === "number") {
navigator.go(to);
return;
}

I tried to add the navigate function as a dependency of useEffect, and it seems working for me.

useEffect(() => {
      navigate(`/users/${id}/other`);
  }, [navigate]);

The documentation didn't tell us to add navigate as a dependency, so I can't assure you that is the right solution.

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

No branches or pull requests

2 participants