remix-run / react-router

Declarative routing for React
https://reactrouter.com
MIT License
52.84k stars 10.23k forks source link

[Bug]: HashRouter returns error when attempting change using anchor links #9946

Closed AaronTweeton closed 1 year ago

AaronTweeton commented 1 year ago

What version of React Router are you using?

6.7.0

Steps to Reproduce

Background: We’re using React Router’s HashRouter for navigating admin pages for a WordPress plugin. Version 6.6.2 works fine, but we discovered the error after upgrading to 6.7.0.

  1. Install React and ReactDOM 17.0.2 with React Router 6.7.0.
  2. Create a React app with a hash router using createHashRouter and createRoutesFromElements.
  3. Create an initial route with path “/“.
  4. Create a nested route with path “child”.
  5. For the initial route’s element, create two links to the nested route, one using React Router’s Link element, and another using the HTML anchor tag (e.g., <a href=“#child”>Child</a>)
  6. Load the app and click both of the links.

Expected Behavior

Clicking on either link, the Link element or the HTML anchor tag should do the same two things:

  1. Update the browser URL.
  2. Trigger the router to display the element.

In version 6.6.2 this is exactly what was happening, which was necessary since we had some links outside the React app that need to link to specific routes within the app.

Actual Behavior

Since 6.7.0, clicking the Link element works as expected, but clicking an anchor tag will:

  1. Update the browser URL.
  2. Not trigger the router to display the element.
  3. Send a warning to the console: You are trying to block a POP navigation to a location that was not created by @remix-run/router. The block will fail silently in production, but in general you should do all navigation with the router (instead of using window.history.pushState directly) to avoid this situation.
timdorr commented 1 year ago

The message will be updated in the next release via #9941

You are trying to perform a POP navigation to a location that was not created by @remix-run/router. This will fail silently in production. You should navigate via the router to avoid this situation (instead of using window.history.pushState/window.location.hash).

You need to be using <Link> for all in-app links. It's perfectly fine to link to the correct path/hash externally (i.e., not on-page links). This is because we are no longer observing hashchange events for our hash routers (data or legacy), so we won't see this event happen. We are instead always using pushState and just encoding/decoding the path depending on the router type. This ensures consistency and enables us to bring back things like useBlocker and usePrompt.

If you really need to do this, you can just ignore the warning (it's only a warning, the code continues to run) and use something like this as a workaround: https://github.com/remix-run/react-router/issues/9940#issuecomment-1397534720

AaronTweeton commented 1 year ago

Thanks Tim for the response! Any recommendations for if I'm trying to link to different routes in the app with links outside the React app, such as in HTML that's outside the root element? We currently use a WordPress submenu that's in PHP outside the React app and uses anchor tags to link to specific routes.

defaude commented 1 year ago

Yeah what if I explicitly want to allow non-react-router-initiated URL changes? I could ignore the warning, but the problem is that no routing is happening.

... and of course it would be nicer to have some kind of opt-in option (i.e. remove warning, activate routing on external URL change).

patrickfatrick commented 1 year ago

Can this be reopened? I ran into this and for my part I was using useHref to generate the href prop passed to a custom anchor tag component (using HashRouter because it's an Electron app). Not a huge deal, I'm able to replace the custom anchor tag with Link, but neither the documentation nor the warning indicates that this intentionally does not work as one would expect.