Skip to content

Commit 5dcc570

Browse files
author
John Pangalos
committed
Wrap route with location arg in location context
In order for the `useLocation` hook to work with the use of the modal pattern, routes with the locationArg prop are wrapped in a LocationContext. This is done conditionally in order to ensure performance in the default case doesn't change.
1 parent 617b27c commit 5dcc570

File tree

4 files changed

+46
-5
lines changed

4 files changed

+46
-5
lines changed

.changeset/hungry-vans-ring.md

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
---
2+
"react-router": patch
3+
"react-router-dom": patch
4+
"react-router-dom-v5-compat": patch
5+
"react-router-native": patch
6+
---
7+
8+
Fix for `useLocation` returning the wrong `Location` when passing a `locationArg` into a `Routes` component.

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -107,7 +107,7 @@
107107
"none": "12 kB"
108108
},
109109
"packages/react-router/dist/umd/react-router.production.min.js": {
110-
"none": "13.5 kB"
110+
"none": "14 kB"
111111
},
112112
"packages/react-router-dom/dist/react-router-dom.production.min.js": {
113113
"none": "10 kB"

packages/react-router/__tests__/useRoutes-test.tsx

Lines changed: 12 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
import * as React from "react";
22
import * as TestRenderer from "react-test-renderer";
33
import type { RouteObject } from "react-router";
4-
import { MemoryRouter, useRoutes } from "react-router";
4+
import { MemoryRouter, useRoutes, useLocation } from "react-router";
55

66
describe("useRoutes", () => {
77
it("returns the matching element from a route config", () => {
@@ -54,9 +54,16 @@ describe("useRoutes", () => {
5454
});
5555

5656
it("Uses the `location` prop instead of context location`", () => {
57+
let TwoComponent = () => {
58+
const location = useLocation();
59+
return <h1>two path:{location.pathname}</h1>;
60+
};
5761
let routes = [
5862
{ path: "one", element: <h1>one</h1> },
59-
{ path: "two", element: <h1>two</h1> },
63+
{
64+
path: "two",
65+
element: <TwoComponent />,
66+
},
6067
];
6168

6269
let renderer: TestRenderer.ReactTestRenderer;
@@ -68,9 +75,11 @@ describe("useRoutes", () => {
6875
);
6976
});
7077

78+
// console.log(renderer.toTree());
7179
expect(renderer.toJSON()).toMatchInlineSnapshot(`
7280
<h1>
73-
two
81+
two path:
82+
/two
7483
</h1>
7584
`);
7685
});

packages/react-router/lib/hooks.tsx

Lines changed: 25 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -408,7 +408,7 @@ export function useRoutes(
408408
);
409409
}
410410

411-
return _renderMatches(
411+
let renderedMatches = _renderMatches(
412412
matches &&
413413
matches.map((match) =>
414414
Object.assign({}, match, {
@@ -423,6 +423,30 @@ export function useRoutes(
423423
parentMatches,
424424
dataRouterStateContext || undefined
425425
);
426+
427+
// When a user passes in a `locationArg` prop, the associated routes need to
428+
// be wrapped in a `LocationContext.Provider` in order for `useLocation` to
429+
// use the `locationArg` location instead of the global location.
430+
if (locationArg) {
431+
return (
432+
<LocationContext.Provider
433+
value={{
434+
location: {
435+
state: undefined,
436+
key: "default",
437+
pathname: "/",
438+
search: "",
439+
hash: "",
440+
...location,
441+
},
442+
navigationType: NavigationType.Pop,
443+
}}
444+
>
445+
{renderedMatches}
446+
</LocationContext.Provider>
447+
);
448+
}
449+
return renderedMatches;
426450
}
427451

428452
function DefaultErrorElement() {

0 commit comments

Comments
 (0)