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]: A router only supports one blocker at a time #12182

Open
philipwisner opened this issue Oct 23, 2024 · 7 comments
Open

[Bug]: A router only supports one blocker at a time #12182

philipwisner opened this issue Oct 23, 2024 · 7 comments
Labels

Comments

@philipwisner
Copy link

What version of React Router are you using?

6.27.0

Steps to Reproduce

I followed the example in the documentation to create a route level blocker using useBlocker. But on the first time it will return that the blocker is blocked and then it will immediately mark it as unblocked. Then all subsequent attempts will work as expected. I have tried many work arounds, and placing the blocker in a different part of the code, having it be more strict, but the same issues keeps happening. I don't know if there any details about how there could be a warning for more than one route blocker and what I can do to prevent that because it seems like that is most likely the cause of the issue.

This is the code I have that will set the blocker.

  let shouldBlock = useCallback(
    ({ currentLocation, nextLocation }) =>
      hasChanges && currentLocation.pathname !== nextLocation.pathname,

    [hasChanges]
  );

  let blocker = useBlocker(shouldBlock);

Link to a video walkthrough of the bug
https://drive.google.com/file/d/1VaxNNyIrG04A3UPeX4uCMLi97GXy-kjx/view?usp=sharing

Expected Behavior

That there would only be a single blocker allowed and that it would return blocked until action was taken to reset or procceed on the blocker.

Actual Behavior

That after a blocked blocker is being set an unblocked blocker is being created right after, only on the first time.

@Azeirah
Copy link

Azeirah commented Oct 28, 2024

I'm seeing a similar issue with blockers. I cannot confirm that the core issue is that there is only one blocker allowed in total, but yes, a blocker that should trigger isn't triggered.

What I found during debugging the react router code is that:

  1. Blockers are set by key in the blockerFunctions Map:

afbeelding

  1. But blockers are not set by key in either the router.state.blockers Map or in the state.blockers Map

afbeelding
afbeelding

In our application code, we are using

import { createBrowserRouter, createRoutesFromElements, Outlet, Route, RouterProvider } from "react-router-dom";

{...}

const router = createBrowserRouter(
  createRoutesFromElements(
    <Route
      element={
        <ErrorFestBoundary>
          <Outlet />
        </ErrorFestBoundary>
      }
    >
      {AppRoutes}
    </Route>
  )
);

{...}

                <RouterProvider router={router} />

Version

npm list | grep react-router
├── [email protected]
├── [email protected]

@nivnahmias
Copy link

nivnahmias commented Oct 29, 2024

For some reason this is an issue that they simply refuse to fix even though there's a pr that fixes the issue completely and has been available for over a year now
#10780

@lauri865
Copy link

I can confirm that we've been running multiple blockers in prod with a patched react-router, and have had exactly 0 issues. The thought of hoisting up blockers makes me want to cry. That seems completely counter to the React ways of building apps, and would only introduce potential bugs.

@depoulo
Copy link

depoulo commented Nov 13, 2024

I'm happily using multiple blockers even without a patch, I just have to copy the logic down to the innermost blocker (use case: #11374 (comment))

@lauri865
Copy link

I'm happily using multiple blockers even without a patch, I just have to copy the logic down to the innermost blocker (use case: #11374 (comment))

Well, not really, are you? It will only ever check one blocker at a time.

@depoulo
Copy link

depoulo commented Nov 14, 2024

I'm happily using multiple blockers even without a patch, I just have to copy the logic down to the innermost blocker (use case: #11374 (comment))

Well, not really, are you? It will only ever check one blocker at a time.

Correct, the innermost one, so I'm copying the logic there. Of course it would be nice to have them execute sequentially from leaf to root, and #10780 shows that it's possible. In my case it's of course a hack, but I'm still optimistic that #11374 will be resolved, otherwise I can still write a context powered withAllParentBlockers() helper function to wrap my blocker code in, still better than forking IMHO.

@lauri865
Copy link

lauri865 commented Nov 14, 2024

Well, what if you need non-nested blockers? Two forms on a page with separate contexts that can render out of order – which blocker will run? Or nested blockers, where the inner-most doesn't need to block, but the outermost does? :)

That sounds like a lot more error-prone, and no new developer on your project will understand what's going on there. Applying a local patch on the other hand took us ~30 seconds. Hopefully it will eventually be merged to the core of react-router, and everything will continue working as is. If not, it's not like we need to update the router very frequently. No-one is forking the project for this, fwiw.

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

5 participants