Skip to content

Commit f3fd217

Browse files
committed
Merge branch 'dev' into brophdawg11/remove-uses
2 parents 8c3431b + 2821817 commit f3fd217

File tree

12 files changed

+304
-189
lines changed

12 files changed

+304
-189
lines changed
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
"react-router": patch
3+
---
4+
5+
Fix bug preventing rendering of descendant `<Routes>` when `RouterProvider` errors existed

.changeset/invalid-link-to.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
"react-router-dom": patch
3+
---
4+
5+
Fail gracefully on `<Link to="//">` and other invalid URL values
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
"react-router": patch
3+
---
4+
5+
Allow `useRevalidator()` to resolve a loader-driven error boundary scenario

package.json

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -108,10 +108,10 @@
108108
"none": "45.8 kB"
109109
},
110110
"packages/react-router/dist/react-router.production.min.js": {
111-
"none": "12.7 kB"
111+
"none": "12.9 kB"
112112
},
113113
"packages/react-router/dist/umd/react-router.production.min.js": {
114-
"none": "15.0 kB"
114+
"none": "15.3 kB"
115115
},
116116
"packages/react-router-dom/dist/react-router-dom.production.min.js": {
117117
"none": "12 kB"

packages/react-router-dom/__tests__/link-href-test.tsx

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -907,4 +907,24 @@ describe("<Link> href", () => {
907907
);
908908
});
909909
});
910+
911+
test("fails gracefully on invalid `to` values", () => {
912+
let warnSpy = jest.spyOn(console, "warn").mockImplementation(() => {});
913+
let renderer: TestRenderer.ReactTestRenderer;
914+
TestRenderer.act(() => {
915+
renderer = TestRenderer.create(
916+
<MemoryRouter>
917+
<Routes>
918+
<Route path="/" element={<Link to="//" />} />
919+
</Routes>
920+
</MemoryRouter>
921+
);
922+
});
923+
924+
expect(renderer.root.findByType("a").props.href).toEqual("//");
925+
expect(warnSpy).toHaveBeenCalledWith(
926+
'<Link to="//"> contains an invalid URL which will probably break when clicked - please update to a valid URL path.'
927+
);
928+
warnSpy.mockRestore();
929+
});
910930
});

packages/react-router-dom/dom.ts

Lines changed: 9 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -183,11 +183,11 @@ export function getFormSubmissionInfo(
183183
let payload: unknown = undefined;
184184

185185
if (isFormElement(target)) {
186-
// When grabbing the action from the element, it will have had the basename
187-
// prefixed to ensure non-JS scenarios work, so strip it since we'll
188-
// re-prefix in the router
189-
let attr = target.getAttribute("action");
190-
action = attr ? stripBasename(attr, basename) : null;
186+
// When grabbing the action from the element, it will have had the basename
187+
// prefixed to ensure non-JS scenarios work, so strip it since we'll
188+
// re-prefix in the router
189+
let attr = target.getAttribute("action");
190+
action = attr ? stripBasename(attr, basename) : null;
191191
method = target.getAttribute("method") || defaultMethod;
192192
encType = target.getAttribute("enctype") || defaultEncType;
193193

@@ -207,11 +207,11 @@ export function getFormSubmissionInfo(
207207

208208
// <button>/<input type="submit"> may override attributes of <form>
209209

210-
// When grabbing the action from the element, it will have had the basename
211-
// prefixed to ensure non-JS scenarios work, so strip it since we'll
212-
// re-prefix in the router
210+
// When grabbing the action from the element, it will have had the basename
211+
// prefixed to ensure non-JS scenarios work, so strip it since we'll
212+
// re-prefix in the router
213213
let attr = target.getAttribute("formaction") || form.getAttribute("action");
214-
action = attr ? stripBasename(attr, basename) : null;
214+
action = attr ? stripBasename(attr, basename) : null;
215215

216216
method =
217217
target.getAttribute("formmethod") ||

packages/react-router-dom/index.tsx

Lines changed: 20 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -451,17 +451,26 @@ export const Link = React.forwardRef<HTMLAnchorElement, LinkProps>(
451451

452452
// Only check for external origins client-side
453453
if (isBrowser) {
454-
let currentUrl = new URL(window.location.href);
455-
let targetUrl = to.startsWith("//")
456-
? new URL(currentUrl.protocol + to)
457-
: new URL(to);
458-
let path = stripBasename(targetUrl.pathname, basename);
459-
460-
if (targetUrl.origin === currentUrl.origin && path != null) {
461-
// Strip the protocol/origin/basename for same-origin absolute URLs
462-
to = path + targetUrl.search + targetUrl.hash;
463-
} else {
464-
isExternal = true;
454+
try {
455+
let currentUrl = new URL(window.location.href);
456+
let targetUrl = to.startsWith("//")
457+
? new URL(currentUrl.protocol + to)
458+
: new URL(to);
459+
let path = stripBasename(targetUrl.pathname, basename);
460+
461+
if (targetUrl.origin === currentUrl.origin && path != null) {
462+
// Strip the protocol/origin/basename for same-origin absolute URLs
463+
to = path + targetUrl.search + targetUrl.hash;
464+
} else {
465+
isExternal = true;
466+
}
467+
} catch (e) {
468+
// We can't do external URL detection without a valid URL
469+
warning(
470+
false,
471+
`<Link to="${to}"> contains an invalid URL which will probably break ` +
472+
`when clicked - please update to a valid URL path.`
473+
);
465474
}
466475
}
467476
}

packages/react-router-dom/server.tsx

Lines changed: 16 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -18,12 +18,17 @@ import {
1818
UNSAFE_convertRoutesToDataRoutes as convertRoutesToDataRoutes,
1919
} from "@remix-run/router";
2020
import { UNSAFE_mapRouteProperties as mapRouteProperties } from "react-router";
21-
import type { Location, RouteObject, To } from "react-router-dom";
22-
import { Routes } from "react-router-dom";
21+
import type {
22+
DataRouteObject,
23+
Location,
24+
RouteObject,
25+
To,
26+
} from "react-router-dom";
2327
import {
2428
createPath,
2529
parsePath,
2630
Router,
31+
useRoutes,
2732
UNSAFE_DataRouterContext as DataRouterContext,
2833
UNSAFE_DataRouterStateContext as DataRouterStateContext,
2934
} from "react-router-dom";
@@ -127,7 +132,7 @@ export function StaticRouterProvider({
127132
navigationType={dataRouterContext.router.state.historyAction}
128133
navigator={dataRouterContext.navigator}
129134
>
130-
<Routes />
135+
<DataRoutes routes={router.routes} />
131136
</Router>
132137
</DataRouterStateContext.Provider>
133138
</DataRouterContext.Provider>
@@ -142,6 +147,14 @@ export function StaticRouterProvider({
142147
);
143148
}
144149

150+
function DataRoutes({
151+
routes,
152+
}: {
153+
routes: DataRouteObject[];
154+
}): React.ReactElement | null {
155+
return useRoutes(routes);
156+
}
157+
145158
function serializeErrors(
146159
errors: StaticHandlerContext["errors"]
147160
): StaticHandlerContext["errors"] {

0 commit comments

Comments
 (0)