diff --git a/.changeset/six-tigers-fold.md b/.changeset/six-tigers-fold.md new file mode 100644 index 0000000000..1745f45816 --- /dev/null +++ b/.changeset/six-tigers-fold.md @@ -0,0 +1,6 @@ +--- +"react-router-dom": patch +"@remix-run/router": patch +--- + +Fix navigation for hash routers on manual URL changes diff --git a/packages/router/history.ts b/packages/router/history.ts index 500ae5e2a1..0a36fcdfd9 100644 --- a/packages/router/history.ts +++ b/packages/router/history.ts @@ -85,7 +85,7 @@ export interface Update { /** * The delta between this location and the former location in the history stack */ - delta: number; + delta: number | null; } /** @@ -612,24 +612,12 @@ function getUrlBasedHistory( } function handlePop() { - let nextAction = Action.Pop; + action = Action.Pop; let nextIndex = getIndex(); - - if (nextIndex != null) { - let delta = nextIndex - index; - action = nextAction; - index = nextIndex; - if (listener) { - listener({ action, location: history.location, delta }); - } - } else { - warning( - false, - `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).` - ); + let delta = nextIndex == null ? null : nextIndex - index; + index = nextIndex; + if (listener) { + listener({ action, location: history.location, delta }); } } diff --git a/packages/router/router.ts b/packages/router/router.ts index a1a626855c..1f56b629e1 100644 --- a/packages/router/router.ts +++ b/packages/router/router.ts @@ -781,12 +781,23 @@ export function createRouter(init: RouterInit): Router { return; } + warning( + activeBlocker != null && delta === null, + "You are trying to use a blocker on a POP navigation to a location " + + "that was not created by @remix-run/router. This will fail silently in " + + "production. This can happen if you are navigating outside the router " + + "via `window.history.pushState`/`window.location.hash` instead of using " + + "router navigation APIs. This can also happen if you are using " + + "createHashRouter and the user manually changes the URL." + ); + let blockerKey = shouldBlockNavigation({ currentLocation: state.location, nextLocation: location, historyAction, }); - if (blockerKey) { + + if (blockerKey && delta != null) { // Restore the URL to match the current UI, but don't update router state ignoreNextHistoryUpdate = true; init.history.go(delta * -1);