Skip to content

Commit f2d0d3d

Browse files
ihabadhamclaude
andcommitted
Use refetchComponent explicitly in retry path
Previous commit's retry path used resetErrorBoundary + onReset state mutation alone — RSCRoute would auto-fetch on the post-reset render because props had changed. Functional, but didn't actually demonstrate useRSC().refetchComponent, which is the canonical RoR Pro RSC retry API per rsc-troubleshooting.md. Switch to: refetchComponent('LiveActivity', correctedProps) primes the cache, then resetErrorBoundary fires; the post-reset render hits cache instead of triggering a second fetch. This shows the explicit API call the docs recommend, while still handling our intentional-error case (refetching with simulateError=false instead of the original throwing props). Page description updated to mention refetchComponent. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
1 parent df039e2 commit f2d0d3d

2 files changed

Lines changed: 29 additions & 25 deletions

File tree

client/app/bundles/server-components/components/LiveActivityRefresher.jsx

Lines changed: 28 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -3,26 +3,12 @@
33
import React, { useState } from 'react';
44
import { ErrorBoundary } from 'react-error-boundary';
55
import RSCRoute from 'react-on-rails-pro/RSCRoute';
6-
7-
function ErrorFallback({ error, resetErrorBoundary }) {
8-
return (
9-
<div className="bg-rose-50 border border-rose-200 rounded-lg p-4">
10-
<p className="text-rose-700 font-semibold mb-1">Server component fetch failed</p>
11-
<p className="text-rose-600 text-sm font-mono mb-3">{error.message}</p>
12-
<button
13-
type="button"
14-
onClick={resetErrorBoundary}
15-
className="px-3 py-1.5 text-sm bg-rose-600 text-white rounded hover:bg-rose-700"
16-
>
17-
Retry
18-
</button>
19-
</div>
20-
);
21-
}
6+
import { useRSC } from 'react-on-rails-pro/RSCProvider';
227

238
const LiveActivityRefresher = () => {
249
const [refreshKey, setRefreshKey] = useState(0);
2510
const [simulateError, setSimulateError] = useState(false);
11+
const { refetchComponent } = useRSC();
2612

2713
const handleRefresh = () => {
2814
setSimulateError(false);
@@ -34,6 +20,18 @@ const LiveActivityRefresher = () => {
3420
setRefreshKey((k) => k + 1);
3521
};
3622

23+
// refetchComponent primes the cache with corrected props before resetting
24+
// the boundary, so the post-reset render hits cache instead of re-fetching.
25+
const buildRetry = (resetErrorBoundary) => () => {
26+
const newKey = refreshKey + 1;
27+
setSimulateError(false);
28+
setRefreshKey(newKey);
29+
refetchComponent('LiveActivity', { simulateError: false, refreshKey: newKey })
30+
// eslint-disable-next-line no-console
31+
.catch((err) => console.error('Retry refetch failed:', err))
32+
.finally(() => resetErrorBoundary());
33+
};
34+
3735
return (
3836
<div className="space-y-3">
3937
<div className="flex items-center gap-2">
@@ -51,16 +49,22 @@ const LiveActivityRefresher = () => {
5149
>
5250
Simulate Error
5351
</button>
54-
<span className="text-xs text-slate-500 ml-2">
55-
Refresh count: {refreshKey}
56-
</span>
52+
<span className="text-xs text-slate-500 ml-2">Refresh count: {refreshKey}</span>
5753
</div>
5854
<ErrorBoundary
59-
FallbackComponent={ErrorFallback}
60-
onReset={() => {
61-
setSimulateError(false);
62-
setRefreshKey((k) => k + 1);
63-
}}
55+
fallbackRender={({ error, resetErrorBoundary }) => (
56+
<div className="bg-rose-50 border border-rose-200 rounded-lg p-4">
57+
<p className="text-rose-700 font-semibold mb-1">Server component fetch failed</p>
58+
<p className="text-rose-600 text-sm font-mono mb-3">{error.message}</p>
59+
<button
60+
type="button"
61+
onClick={buildRetry(resetErrorBoundary)}
62+
className="px-3 py-1.5 text-sm bg-rose-600 text-white rounded hover:bg-rose-700"
63+
>
64+
Retry
65+
</button>
66+
</div>
67+
)}
6468
resetKeys={[refreshKey]}
6569
>
6670
<RSCRoute componentName="LiveActivity" componentProps={{ simulateError, refreshKey }} />

client/app/bundles/server-components/ror_components/ServerComponentsPage.jsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -72,7 +72,7 @@ const ServerComponentsPage = ({ comments = [] }) => {
7272
state plumbing. Click <strong>Simulate Error</strong> to make the server component
7373
throw; the failure surfaces as <code>ServerComponentFetchError</code> and is
7474
caught by <code>&lt;ErrorBoundary&gt;</code>, which renders a Retry button that
75-
re-fetches with corrected props.
75+
calls <code>refetchComponent</code> with corrected props.
7676
</p>
7777
<LiveActivityRefresher />
7878
</section>

0 commit comments

Comments
 (0)