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]: Getting "A router only supports one blocker at a time" warning when running your navigation-blocking example #11430

Open
simonbaas opened this issue Apr 9, 2024 · 11 comments
Labels

Comments

@simonbaas
Copy link

simonbaas commented Apr 9, 2024

What version of React Router are you using?

6.22.3

Steps to Reproduce

  1. Clone react-router repo and navigate into examples/navigation-blocking
  2. Update react-router-dom to 6.22.3 (same issue on ^6.21.0 though)
  3. Run npm install
  4. Start dev server: npm run dev
  5. On page go to http://localhost:3000/three (Three (Form with blocker)
  6. In code editor, press save on app.tsx so vite HMR runs
  7. Go back to web page and click on another link
  8. Notice warning in console

Expected Behavior

Not getting the warning. Any blocker should be disposed/cleaned up correctly.

Actual Behavior

Getting warning "A router only supports one blocker at a time" in console.

I'm seeing this issue in real world case as well, even if useBlocker is only called once in the entire app. It the component which calls useBlocker is "mounted" (in lack of better term) and the router is re-created higher up it seems like the old blocker is not disposed/removed/cleanup correctly.

@simonbaas simonbaas added the bug label Apr 9, 2024
@elvince
Copy link

elvince commented Apr 19, 2024

Hi,
I'm facing exactly this bug also.

If a new router is recreated while a useBlocker is "active/mounted", it is not reseted properly.

Thanks for your help in fixing this.

@JasonDyke
Copy link

I've been seeing this same issue for a while now, but after updating to react-router-dom v6.23.0 today I haven't seen it again.

Can anyone else confirm that this issue is fixed in 6.23.0?

@Jose4gg
Copy link

Jose4gg commented Apr 26, 2024

@JasonDyke it is still happening to me in 6.23.0

@simonbaas
Copy link
Author

Same issue still exists on 6.23.0.

@kubmir
Copy link

kubmir commented Apr 28, 2024

Same issue for me on 6.23.0. In fact, it also really prevents navigation for me. The last version which worked for me was 6.13.0 - all versions since then breaks navigation after form submission for me.

@elvince
Copy link

elvince commented Apr 29, 2024

Same issue still exists on 6.23.0.

@ptim
Copy link

ptim commented May 3, 2024

Not sure if this is a valid solution, but I notice in the example:
https://github.com/remix-run/react-router/blob/main/examples/navigation-blocking/src/app.tsx#L42

if (import.meta.hot) {
  import.meta.hot.dispose(() => router.dispose());
}

...seems to resolve the warning for me

@simonbaas
Copy link
Author

I see that the import.meta.hot.dispose(...) function is called in the example, but it doesn't solve the issue because you still get the "A router only supports one blocker at a time" message in the browser dev console if you follow the steps mentioned in the original post above. (Just re-tested it with version 6.24.0).

Also, this could only be a potential solution for when in development mode and because the issue also is present when "a new router is recreated while a useBlocker is "active/mounted"" (as mentioned above as well) it's not a valid solution imho.

@samuelblattner
Copy link

We have the same issue, because our routes depend on a state and recreate the router whenever this state changes. As a temporary fix, we create the router only when the module is loaded and pass route updates via _internalSetRoutes, which clearly is a hack. But it seems to do the job for now...

@abentele
Copy link

abentele commented Sep 9, 2024

same problem here, with react-router 6.26.1: if I change something in code (with hot-reload in Browser) while a useBlocker is mounted, the warning "A router only supports one blocker at a time" is printed.

=> the conclusion of @simonbaas seems to be the most reasonable related to my issue.

And no, it's not a solution to dispose the router on hot reload like mentioned above.

@simaks
Copy link

simaks commented Sep 12, 2024

I have same problem. After hot reload while in page with active useBlocker, the links stop working and I get warning message in console "A router only supports one blocker at a time".

What I figured out is that my shouldBlock = useCallback function is cached with some "blocked" state that tells the blocker to block. So as a workaround I tried to add a ref which worked:

  const isMountedRef = useRef<boolean>();
  useEffect(() => {
    isMountedRef.current = true;
    return () => {
      isMountedRef.current = false;
    };
  }, []);

  const shouldBlock = useCallback<BlockerFunction>(
    ({ currentLocation, nextLocation }) => {
      return (
        isMountedRef.current &&
        currentLocation.pathname !== nextLocation.pathname
        // your other blocking conditions here
      );
    },
    [state],
  );

  const blocker = useBlocker(shouldBlock);

That doesn't solve the warning though

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

9 participants