Skip to content

Commit 5012b94

Browse files
committed
enhance thrown redirects on the client
1 parent 6eb2390 commit 5012b94

File tree

3 files changed

+39
-9
lines changed

3 files changed

+39
-9
lines changed

packages/react-router/lib/hooks.tsx

Lines changed: 11 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1090,7 +1090,7 @@ export class RenderErrorBoundary extends React.Component<
10901090
}
10911091
}
10921092

1093-
const errorRedirectHandledMap = new WeakMap<any, boolean>();
1093+
const errorRedirectHandledMap = new WeakMap<any, Promise<void>>();
10941094
function RSCErrorHandler({
10951095
children,
10961096
error,
@@ -1099,7 +1099,6 @@ function RSCErrorHandler({
10991099
error: unknown;
11001100
}) {
11011101
let { basename } = React.useContext(NavigationContext);
1102-
let navigate = useNavigate();
11031102

11041103
if (
11051104
typeof error === "object" &&
@@ -1109,22 +1108,25 @@ function RSCErrorHandler({
11091108
) {
11101109
let redirect = decodeRedirectErrorDigest(error.digest);
11111110
if (redirect) {
1111+
let existingRedirect = errorRedirectHandledMap.get(error);
1112+
if (existingRedirect) throw existingRedirect;
1113+
11121114
let parsed = parseToInfo(redirect.location, basename);
11131115

11141116
if (isBrowser && !errorRedirectHandledMap.get(error)) {
1115-
errorRedirectHandledMap.set(error, true);
1116-
11171117
if (parsed.isExternal || redirect.reloadDocument) {
11181118
window.location.href = parsed.absoluteURL || parsed.to;
11191119
} else {
1120-
// @ts-expect-error - Needs React 19 types
1121-
React.startTransition(() => {
1122-
return navigate(parsed.to, {
1120+
const redirectPromise: Promise<void> = Promise.resolve().then(() =>
1121+
window.__reactRouterDataRouter!.navigate(parsed.to, {
11231122
replace: redirect.replace,
1124-
});
1125-
});
1123+
}),
1124+
);
1125+
errorRedirectHandledMap.set(error, redirectPromise);
1126+
throw redirectPromise;
11261127
}
11271128
}
1129+
11281130
return (
11291131
<meta
11301132
httpEquiv="refresh"

playground/rsc-vite/src/routes.ts

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,11 @@ export const routes = [
1616
path: "about",
1717
lazy: () => import("./routes/about/about"),
1818
},
19+
{
20+
id: "render-redirect",
21+
path: "render-redirect/:id?",
22+
lazy: () => import("./routes/render-redirects"),
23+
},
1924
{
2025
id: "parent",
2126
path: "parent",
Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
import { Link, redirect } from "react-router";
2+
3+
export default function RenderRedirect({
4+
params: { id },
5+
}: {
6+
params: { id?: string };
7+
}) {
8+
if (id === "redirect") {
9+
throw redirect("/render-redirect/redirected");
10+
}
11+
12+
if (id === "external") {
13+
throw redirect("https://example.com/");
14+
}
15+
16+
return (
17+
<>
18+
<h1>{id || "home"}</h1>
19+
<Link to="/render-redirect/redirect">Redirect</Link>
20+
<Link to="/render-redirect/external">External</Link>
21+
</>
22+
);
23+
}

0 commit comments

Comments
 (0)