Core Data Fetching
The Core Data Fetching module provides the foundational React hook, useSWR, which implements the stale-while-revalidate (SWR) strategy for efficient data fetching, caching, and state management. It is designed to simplify asynchronous data operations in React applications by offering automatic cache management, revalidation triggers, suspense support, and error handling mechanisms.
Overview and Purpose
At its core, this module exists to solve common challenges in client-side data fetching:
Avoiding unnecessary network requests by caching previously fetched data.
Keeping data fresh by automatically revalidating cached data in the background.
Providing a declarative and ergonomic API that integrates with React's rendering lifecycle.
Supporting advanced scenarios such as suspense rendering, error boundaries, and manual retries.
Enabling extensibility via configuration and middleware.
This results in better performance, user experience, and developer productivity when working with asynchronous data in React.
How the Module Works
useSWR Hook
The heart of the module is the useSWR hook, implemented in src/index/use-swr.ts. It accepts a key (which uniquely identifies the data resource), a fetcher function (which performs the asynchronous data retrieval), and an optional configuration object.
const useSWR = withArgs<SWRHook>(useSWRHandler)
Here, useSWR is a wrapper around the internal handler useSWRHandler which contains the detailed logic.
Key Functionalities and Workflow
Key Serialization and Cache Access
The key can be any type (string, array, etc.) and is serialized internally to a stable string representation by the
serializeutility. This serialized key is used as the unique identifier for caching and subscription management.const [key, fnArg] = serialize(_key)The cache helper (
createCacheHelper) provides methods to get, set, and subscribe to cached state associated with the key.Cache State and Snapshot Selection
The hook uses
useSyncExternalStoreto subscribe React components to changes in the cached state for the key. It maintains a snapshot of the current state (data,error,isValidating,isLoading) and carefully manages equality checks to avoid unnecessary re-renders.The snapshot selection also considers whether a request should be initiated (e.g., depending on
revalidateOnMount,suspense, or pause state).Fallback Data and Suspense Handling
If no cached data exists, the hook supports fallback data provided inline or from a global config. If the fallback is a promise, React Suspense integration is enabled by throwing the promise to suspend rendering until resolution.
In suspense mode, missing data or errors cause the hook to throw promises or errors to the React Suspense/ErrorBoundary system.
Revalidation Logic
The
revalidatefunction wraps the fetcher function with logic to:Prevent duplicate requests within the deduplication interval.
Manage concurrency and race conditions by tracking request timestamps.
Update cache state during loading, success, and error states.
Support retry logic on errors with configurable backoff and retry counts.
Trigger relevant lifecycle callbacks (
onSuccess,onError,onDiscarded,onLoadingSlow).
This function is carefully memoized and exposed to the user via the
mutateAPI for manual data updates.Global Event Subscriptions
The hook listens to global events such as window focus and network reconnect to trigger automatic revalidation if enabled via configuration (
revalidateOnFocus,revalidateOnReconnect).Event subscriptions are managed via a centralized global state (
SWRGlobalState) and cleaned up on component unmount.Polling Support
If a
refreshIntervalis configured, the hook sets up a timer to periodically revalidate the data as long as the page is visible, online, and no error exists.State Exposure
The hook returns an object exposing:
data: The current cached or fallback data.error: Any error encountered during fetching.isValidating: Whether a request is ongoing.isLoading: Whether the data is loading for the first time.mutate: A function to manually update or revalidate the cached data.
Interactions with Other Modules
Global Cache and State (
src/_internal/utils/cache.ts)The core fetching logic relies on a cache provider interface that stores data keyed by serialized keys. This cache is managed globally via
SWRGlobalStatewhich tracks event listeners, mutation state, and revalidation callbacks.The cache initialization function
initCachecreates or retrieves global state associated with a cache provider, sets up subscription mechanisms, and installs event listeners for focus and reconnect events.Configuration and Middleware (
src/_internal/index.ts)The hook uses a global SWR configuration context to provide defaults and extend behavior via middleware. This includes options for deduplication intervals, retry strategies, suspense support, and more.
Mutation and Revalidation (
internalMutatein utils/mutate)The
mutatefunction exposed by the hook wraps an internal mutation mechanism that updates cache state and triggers revalidation as needed.Serialization Utilities
The serialization of keys is critical to maintain stable cache keys and support complex key types (arrays, functions, etc.).
Important Concepts and Design Patterns
Stale-While-Revalidate Strategy
The core idea is to serve cached data immediately ("stale") and simultaneously fetch fresh data in the background ("revalidate"). This balances fast UI updates with data freshness.
Deduplication and Concurrency Control
Multiple components may request the same data simultaneously. The hook deduplicates these requests within a configurable interval, ensuring only one network request per key runs at a time. It uses timestamps to identify and ignore outdated request results.
Suspense Integration
By throwing promises during data fetching, the hook integrates seamlessly with React's Suspense feature, enabling declarative loading states without manual state management.
Subscription Model
The system subscribes React components to cache changes via useSyncExternalStore and custom subscription callbacks, ensuring efficient updates and minimal re-renders.
Extensibility via Configuration
The hook is highly configurable, supporting features like:
Automatic revalidation on focus and reconnect.
Polling at configurable intervals.
Retry with backoff strategies.
Pausing fetching when offline or manually.
Fallback data and optimistic UI patterns.
Code Snippets Illustrating Key Points
Revalidation Triggered by Focus Event
const onRevalidate = (type: RevalidateEvent, opts = {}) => {
if (type == revalidateEvents.FOCUS_EVENT) {
if (getConfig().revalidateOnFocus && isActive()) {
softRevalidate() // calls revalidate()
}
}
// ...other event handlers
}
subscribeCallback(key, EVENT_REVALIDATORS, onRevalidate)
This snippet shows how the hook listens to global focus events and triggers revalidation when the app regains focus.
Returning State via useSyncExternalStore
const cached = useSyncExternalStore(
(callback) => subscribeCache(key, (curr, prev) => {
if (!isEqual(prev, curr)) callback()
}),
getSnapshot[0],
getSnapshot[1]
)
This ensures React components efficiently subscribe to the cache state for the key and update when relevant parts of the state change.
Suspense Mode Data Handling
if (suspense) {
if (hasKeyButNoData) {
if (!isUndefined(error)) throw error
throw revalidate(WITH_DEDUPE) // suspends React rendering
}
}
When in suspense mode, the hook either throws errors to an error boundary or suspends by throwing a promise to a Suspense boundary while data is loading.
Mermaid Sequence Diagram: Core useSWR Data Fetching and Revalidation Flow
sequenceDiagram
participant Comp as React Component
participant useSWR as useSWR Hook
participant Cache as Global Cache
participant Fetcher as Fetcher Function
participant Events as Global Events (Focus/Reconnect)
Comp->>useSWR: Mount + call with key & fetcher
useSWR->>Cache: Subscribe to cached state by key
Cache-->>useSWR: Return cached data or fallback
alt Data missing or stale
useSWR->>Fetcher: Call fetcher to get data
Fetcher-->>useSWR: Return fresh data or error
useSWR->>Cache: Update cache with new data/error
Cache-->>Comp: Notify subscribers of update
else Cached data valid
Cache-->>Comp: Return cached data immediately
end
Events->>useSWR: Focus or reconnect event triggers
useSWR->>Fetcher: Revalidate data (deduped)
Fetcher-->>useSWR: Return fresh data or error
useSWR->>Cache: Update cache
Cache-->>Comp: Notify subscribers
Comp->>useSWR: Calls mutate() manually
useSWR->>Cache: Updates cache and optionally revalidates
This diagram visualizes the lifecycle of data fetching, cache subscription, background revalidation triggered by events, and manual cache mutation.
Summary
The Core Data Fetching module is the foundational piece enabling declarative, efficient, and robust data fetching via the useSWR hook. It balances immediate responsiveness with data freshness by leveraging cache, revalidation, and concurrency control. Its design integrates deeply with React’s rendering model, supporting suspense and error boundaries, while exposing flexible configuration and extensibility points for a wide range of real-world use cases.