Skip to content

Commit 658235f

Browse files
Fix RSC bug where outlets replace routes that skip revalidation (#14071)
1 parent 59522ba commit 658235f

File tree

3 files changed

+35
-28
lines changed

3 files changed

+35
-28
lines changed

.changeset/young-beans-sneeze.md

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 RSC Data Mode issue where routes that return `false` from `shouldRevalidate` would be replaced by an `<Outlet />`

integration/client-data-test.ts

Lines changed: 1 addition & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -958,14 +958,9 @@ test.describe("Client Data", () => {
958958
console.error = _consoleError;
959959
});
960960

961-
test("hydrating clientLoader redirects trigger new .data requests to the server", async ({
961+
test("hydrating clientLoader redirects trigger new data requests to the server", async ({
962962
page,
963963
}) => {
964-
test.fixme(
965-
templateName.includes("rsc"),
966-
"Not working in the RSC implementation",
967-
);
968-
969964
appFixture = await createAppFixture(
970965
await createFixture({
971966
templateName,

packages/react-router/lib/rsc/server.rsc.ts

Lines changed: 29 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -984,22 +984,15 @@ async function getRenderPayload(
984984

985985
let matchesPromise = Promise.all(
986986
staticContext.matches.map((match, i) => {
987-
// Only bother rendering Server Components for routes that we're surfacing,
988-
// so nothing at/below an error boundary and prune routes if included in
989-
// `routeIdsToLoad`. This is specifically important when a middleware
990-
// or loader throws and we don't have any `loaderData` to pass through as
991-
// props leading to render-time errors of the server component
992-
let shouldRenderComponent =
993-
i <= deepestRenderedRouteIdx &&
994-
(!routeIdsToLoad || routeIdsToLoad.includes(match.route.id)) &&
995-
(!staticContext.errors || !(match.route.id in staticContext.errors));
996-
997-
return getRSCRouteMatch(
987+
let isBelowErrorBoundary = i > deepestRenderedRouteIdx;
988+
let parentId = parentIds[match.route.id];
989+
return getRSCRouteMatch({
998990
staticContext,
999991
match,
1000-
shouldRenderComponent,
1001-
parentIds[match.route.id],
1002-
);
992+
routeIdsToLoad,
993+
isBelowErrorBoundary,
994+
parentId,
995+
});
1003996
}),
1004997
);
1005998

@@ -1019,12 +1012,19 @@ async function getRenderPayload(
10191012
};
10201013
}
10211014

1022-
async function getRSCRouteMatch(
1023-
staticContext: StaticHandlerContext,
1024-
match: AgnosticDataRouteMatch,
1025-
shouldRenderComponent: boolean,
1026-
parentId: string | undefined,
1027-
) {
1015+
async function getRSCRouteMatch({
1016+
staticContext,
1017+
match,
1018+
isBelowErrorBoundary,
1019+
routeIdsToLoad,
1020+
parentId,
1021+
}: {
1022+
staticContext: StaticHandlerContext;
1023+
match: AgnosticDataRouteMatch;
1024+
isBelowErrorBoundary: boolean;
1025+
routeIdsToLoad: string[] | null;
1026+
parentId: string | undefined;
1027+
}) {
10281028
// @ts-expect-error - FIXME: Fix the types here
10291029
await explodeLazyRoute(match.route);
10301030
const Layout = (match.route as any).Layout || React.Fragment;
@@ -1036,8 +1036,15 @@ async function getRSCRouteMatch(
10361036
const params = match.params;
10371037
// TODO: DRY this up once it's fully fleshed out
10381038
let element: React.ReactElement | undefined = undefined;
1039-
if (Component) {
1040-
element = shouldRenderComponent
1039+
let shouldLoadRoute =
1040+
!routeIdsToLoad || routeIdsToLoad.includes(match.route.id);
1041+
// Only bother rendering Server Components for routes that we're surfacing,
1042+
// so nothing at/below an error boundary and prune routes if included in
1043+
// `routeIdsToLoad`. This is specifically important when a middleware
1044+
// or loader throws and we don't have any `loaderData` to pass through as
1045+
// props leading to render-time errors of the server component
1046+
if (Component && shouldLoadRoute) {
1047+
element = !isBelowErrorBoundary
10411048
? React.createElement(
10421049
Layout,
10431050
null,

0 commit comments

Comments
 (0)