Skip to content

Commit debdf3e

Browse files
authored
fix: retain transition through form submission to allow useOptimistic to play correctly with pending states (#13964)
1 parent a3fc04b commit debdf3e

File tree

2 files changed

+53
-42
lines changed

2 files changed

+53
-42
lines changed

.changeset/fuzzy-bottles-itch.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+
retain transition through form submission to allow useOptimistic to play correctly with pending states

packages/react-router/lib/rsc/browser.tsx

Lines changed: 48 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -114,53 +114,59 @@ export function createCallServer({
114114
}
115115

116116
if (payload.rerender) {
117-
(async () => {
118-
const rerender = await payload.rerender;
119-
if (!rerender) return;
120-
121-
if (landedActionId < actionId && window.__routerActionID <= actionId) {
122-
landedActionId = actionId;
123-
124-
if (rerender.type === "redirect") {
125-
if (rerender.reload) {
126-
window.location.href = rerender.location;
117+
React.startTransition(
118+
// @ts-expect-error - We have old react types that don't know this can be async
119+
async () => {
120+
const rerender = await payload.rerender;
121+
if (!rerender) return;
122+
123+
if (
124+
landedActionId < actionId &&
125+
window.__routerActionID <= actionId
126+
) {
127+
landedActionId = actionId;
128+
129+
if (rerender.type === "redirect") {
130+
if (rerender.reload) {
131+
window.location.href = rerender.location;
132+
return;
133+
}
134+
window.__router.navigate(rerender.location, {
135+
replace: rerender.replace,
136+
});
127137
return;
128138
}
129-
window.__router.navigate(rerender.location, {
130-
replace: rerender.replace,
131-
});
132-
return;
133-
}
134139

135-
let lastMatch: RSCRouteManifest | undefined;
136-
for (const match of rerender.matches) {
137-
window.__router.patchRoutes(
138-
lastMatch?.id ?? null,
139-
[createRouteFromServerManifest(match)],
140-
true
141-
);
142-
lastMatch = match;
143-
}
144-
window.__router._internalSetStateDoNotUseOrYouWillBreakYourApp({});
145-
146-
React.startTransition(() => {
147-
window.__router._internalSetStateDoNotUseOrYouWillBreakYourApp({
148-
loaderData: Object.assign(
149-
{},
150-
window.__router.state.loaderData,
151-
rerender.loaderData
152-
),
153-
errors: rerender.errors
154-
? Object.assign(
155-
{},
156-
window.__router.state.errors,
157-
rerender.errors
158-
)
159-
: null,
140+
let lastMatch: RSCRouteManifest | undefined;
141+
for (const match of rerender.matches) {
142+
window.__router.patchRoutes(
143+
lastMatch?.id ?? null,
144+
[createRouteFromServerManifest(match)],
145+
true
146+
);
147+
lastMatch = match;
148+
}
149+
window.__router._internalSetStateDoNotUseOrYouWillBreakYourApp({});
150+
151+
React.startTransition(() => {
152+
window.__router._internalSetStateDoNotUseOrYouWillBreakYourApp({
153+
loaderData: Object.assign(
154+
{},
155+
window.__router.state.loaderData,
156+
rerender.loaderData
157+
),
158+
errors: rerender.errors
159+
? Object.assign(
160+
{},
161+
window.__router.state.errors,
162+
rerender.errors
163+
)
164+
: null,
165+
});
160166
});
161-
});
167+
}
162168
}
163-
})();
169+
);
164170
}
165171

166172
return payload.actionResult;

0 commit comments

Comments
 (0)