manual-retry-mutate.tsx
Overview
The manual-retry-mutate.tsx file implements a React component that demonstrates a robust pattern for data fetching with error handling and manual retry capabilities using SWR (stale-while-revalidate). It combines React Suspense for asynchronous data loading, react-error-boundary for error capturing and fallback UI presentation, and SWR’s mutate function to manually trigger data refetching.
This component fetches data from a remote API endpoint (/api/retry), intentionally fails on the first attempt to simulate errors, and allows users to retry fetching manually through a UI button. The integration of Suspense and ErrorBoundary ensures smooth user experience by handling loading states and errors declaratively.
Detailed Explanation
Module Imports
Suspensefrom React: Enables declarative waiting for asynchronous operations.ErrorBoundaryfromreact-error-boundary: Catches errors thrown by child components and renders a fallback UI.useSWRandmutatefromswr: Hooks and utilities for remote data fetching with cache management and revalidation.
Variables and Constants
let count = 0
const key = 'manual-retry-mutate'
count: A counter used inside the fetcher to simulate a failure on the first fetch attempt.key: A unique SWR cache key identifying the resource.
Function: fetcher
export const fetcher = () => {
count++
if (count === 1) return Promise.reject('wrong')
return fetch('/api/retry')
.then(r => r.json())
.then(r => r.name)
}
Purpose: Fetches remote data asynchronously.
Behavior:
On the first call (
count === 1), it rejects the promise to simulate an error.On subsequent calls, it fetches from
/api/retry, parses the JSON response, and returns thenameproperty.
Return value: A
Promiseresolving to a string (thenamefield) or rejecting with an error.
Usage Example:
fetcher()
.then(data => console.log(data))
.catch(error => console.error(error))
Hook: useRemoteData
export const useRemoteData = () =>
useSWR(key, fetcher, {
suspense: true
})
Purpose: Custom React hook to fetch remote data using SWR with Suspense support.
Parameters: None.
Returns: The SWR response object including the
datafield.Configuration:
Suspense enabled (
suspense: true), so the hook suspends rendering until data is ready or throws an error.
Usage:
const { data } = useRemoteData()
// use `data` safely; component suspends if data not ready
Component: Demo
const Demo = () => {
const { data } = useRemoteData()
return <div>data: {data}</div>
}
Purpose: Displays the fetched data.
Behavior:
Calls
useRemoteDatato get data.Renders a simple
<div>showing the data.
Error & Loading Handling:
Relies on parent
SuspenseandErrorBoundarycomponents to manage loading and error states.
Component: Fallback
function Fallback({ resetErrorBoundary }: any) {
return (
<div role="alert">
<p>Something went wrong</p>
<button
onClick={async () => {
await mutate(key, fetcher)
resetErrorBoundary()
}}
>
retry
</button>
</div>
)
}
Purpose: Rendered UI shown when an error occurs during data fetching.
Props:
resetErrorBoundary(function) — Provided byreact-error-boundaryto reset the error state.
UI Elements:
Error message.
Retry button.
Retry Logic:
On button click, calls
mutate(key, fetcher)to manually revalidate (refetch) the data.After mutation completes, calls
resetErrorBoundary()to clear the error and allow the component tree to re-render.
Usage: Passed as the
FallbackComponenttoErrorBoundary.
Component: RemoteData (Default Export)
function RemoteData() {
return (
<div className="App">
<ErrorBoundary FallbackComponent={Fallback}>
<Suspense fallback={<div>loading</div>}>
<Demo />
</Suspense>
</ErrorBoundary>
</div>
)
}
Purpose: Top-level component that orchestrates data fetching, error handling, and loading states.
Structure:
Wraps the
Democomponent inside:Suspensewith a fallback UI of<div>loading</div>shown while data is loading.ErrorBoundarywith theFallbackcomponent to catch and handle errors.
Behavior:
When
useRemoteDatasuspends, Suspense displays "loading".When
useRemoteDatathrows an error, ErrorBoundary rendersFallback.On retry from
Fallback, the data is re-fetched and the error boundary resets.
Export: Default export of the module.
Important Implementation Details and Algorithms
Simulated Failure on First Fetch:
Thefetcherfunction deliberately rejects the promise on the first call to simulate an error scenario. This is useful for demonstrating retry and error handling logic.Manual Retry via
mutate:
The retry button triggersmutate(key, fetcher), which:Revalidates the data by calling
fetcher.Updates SWR’s cache.
Causes dependent components to re-render with fresh data.
Suspense + ErrorBoundary Integration:
useSWRwithsuspense: truethrows promises to suspend rendering until data is ready.Errors during fetching are thrown and caught by
ErrorBoundary.This pattern provides declarative control over loading and error states without imperative state management.
Error Boundary Reset:
TheresetErrorBoundaryfunction resets the internal error state ofErrorBoundary, allowing child components to attempt rendering again, crucial for retry workflows.
Interaction with Other Parts of the System
SWR Library:
Provides core data fetching, caching, and revalidation capabilities.React Suspense:
Coordinates asynchronous rendering by suspending components until promises resolve.React Error Boundary (
react-error-boundary):
Catches errors in React component trees and renders fallback UI.API Endpoint (
/api/retry):
The remote data source the fetcher queries.Global Cache (via SWR):
mutateupdates the global cache, allowing manual retries to refresh data.User Interface:
Presents loading states, errors, and retry controls for better UX.
Usage Example
import RemoteData from './manual-retry-mutate'
// In your app render tree
function App() {
return <RemoteData />
}
The user will see:
"loading" initially.
Then, since the first fetch fails, the fallback UI with "Something went wrong" and a retry button.
Clicking "retry" triggers a manual fetch and will succeed on subsequent fetches, showing the data.
Visual Diagram - Component Interaction
componentDiagram
component RemoteData {
+render()
}
component ErrorBoundary {
+FallbackComponent
}
component Suspense {
+fallback
}
component Demo {
+render()
}
component useRemoteData {
+fetch data (suspense enabled)
}
component fetcher {
+fetch('/api/retry')
+simulate failure first call
}
component mutate {
+manual revalidation
}
RemoteData --> ErrorBoundary : wraps
ErrorBoundary --> Fallback : onError
RemoteData --> Suspense : wraps
Suspense --> Demo : wraps
Demo --> useRemoteData : calls
useRemoteData --> fetcher : fetches
Fallback --> mutate : on retry button click
mutate --> fetcher : calls
Summary
The manual-retry-mutate.tsx file demonstrates a best-practice React pattern for data fetching with Suspense, error boundaries, and manual retry using SWR:
It simulates a failure scenario on first fetch to test retry handling.
Uses
useSWRwith Suspense to suspend UI rendering gracefully.Wraps components in
ErrorBoundaryto catch errors and show a fallback UI.Implements a retry button that triggers SWR's
mutateto manually re-fetch data and resets the error state.Provides a clean and user-friendly way to recover from transient errors without page reloads.
This pattern is valuable in scalable React applications requiring robust data fetching and error recovery mechanisms.