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:

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

  1. 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 serialize utility. 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.

  2. Cache State and Snapshot Selection

    The hook uses useSyncExternalStore to 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).

  3. 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.

  4. Revalidation Logic

    The revalidate function 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 mutate API for manual data updates.

  5. 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.

  6. Polling Support

    If a refreshInterval is configured, the hook sets up a timer to periodically revalidate the data as long as the page is visible, online, and no error exists.

  7. 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


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:


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.