From e766ab5a286376bc26356a322e7ad95a11aa3d41 Mon Sep 17 00:00:00 2001 From: John Pangalos Date: Mon, 12 Sep 2022 19:08:41 +0200 Subject: [PATCH] fix: Wrap route with location arg in location context (#9094) * 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. * Update useLocation unit tests * Remove static markup from test for brevity * Back out formatting change to test Co-authored-by: John Pangalos Co-authored-by: Matt Brophy --- .changeset/hungry-vans-ring.md | 8 ++++ .../__tests__/useLocation-test.tsx | 45 ++++++++++++++++--- packages/react-router/lib/hooks.tsx | 29 +++++++++++- 3 files changed, 75 insertions(+), 7 deletions(-) create mode 100644 .changeset/hungry-vans-ring.md diff --git a/.changeset/hungry-vans-ring.md b/.changeset/hungry-vans-ring.md new file mode 100644 index 0000000000..cbfe75bedc --- /dev/null +++ b/.changeset/hungry-vans-ring.md @@ -0,0 +1,8 @@ +--- +"react-router": patch +"react-router-dom": patch +"react-router-dom-v5-compat": patch +"react-router-native": patch +--- + +fix: update `useLocation` to return the scoped `Location` when inside a `` component diff --git a/packages/react-router/__tests__/useLocation-test.tsx b/packages/react-router/__tests__/useLocation-test.tsx index 7da12f1a12..2c7cfa6c69 100644 --- a/packages/react-router/__tests__/useLocation-test.tsx +++ b/packages/react-router/__tests__/useLocation-test.tsx @@ -2,9 +2,9 @@ import * as React from "react"; import * as TestRenderer from "react-test-renderer"; import { MemoryRouter, Routes, Route, useLocation } from "react-router"; -function ShowPath() { - let { pathname, search, hash } = useLocation(); - return
{JSON.stringify({ pathname, search, hash })}
; +function ShowLocation() { + let location = useLocation(); + return
{JSON.stringify(location)}
; } describe("useLocation", () => { @@ -14,7 +14,7 @@ describe("useLocation", () => { renderer = TestRenderer.create( - } /> + } /> ); @@ -22,8 +22,43 @@ describe("useLocation", () => { expect(renderer.toJSON()).toMatchInlineSnapshot(`
-        {"pathname":"/home","search":"?the=search","hash":"#the-hash"}
+        {"pathname":"/home","search":"?the=search","hash":"#the-hash","state":null,"key":"default"}
       
`); }); + + it("returns the scoped location object when nested in ", () => { + let renderer: TestRenderer.ReactTestRenderer; + TestRenderer.act(() => { + renderer = TestRenderer.create( + + + + ); + }); + + function App() { + return ( +
+ + } /> + + + } /> + +
+ ); + } + + expect(renderer.toJSON()).toMatchInlineSnapshot(` +
+
+          {"pathname":"/home","search":"?the=search","hash":"#the-hash","state":null,"key":"default"}
+        
+
+          {"pathname":"/scoped","search":"?scoped=search","hash":"#scoped-hash","state":null,"key":"default"}
+        
+
+ `); + }); }); diff --git a/packages/react-router/lib/hooks.tsx b/packages/react-router/lib/hooks.tsx index be11367d08..020e0c63be 100644 --- a/packages/react-router/lib/hooks.tsx +++ b/packages/react-router/lib/hooks.tsx @@ -8,9 +8,9 @@ import type { PathPattern, Router as RemixRouter, To, - Action as NavigationType, } from "@remix-run/router"; import { + Action as NavigationType, invariant, isRouteErrorResponse, joinPaths, @@ -425,7 +425,7 @@ export function useRoutes( ); } - return _renderMatches( + let renderedMatches = _renderMatches( matches && matches.map((match) => Object.assign({}, match, { @@ -440,6 +440,31 @@ export function useRoutes( parentMatches, dataRouterStateContext || undefined ); + + // When a user passes in a `locationArg`, the associated routes need to + // be wrapped in a new `LocationContext.Provider` in order for `useLocation` + // to use the scoped location instead of the global location. + if (locationArg) { + return ( + + {renderedMatches} + + ); + } + + return renderedMatches; } function DefaultErrorElement() {