index.ts


Overview

The index.ts file in the subscription module of the SWR (stale-while-revalidate) ecosystem implements middleware and hooks that enable React components to subscribe to external real-time data sources. It extends the core SWR hook functionality by adding subscription management with reference counting and lifecycle controls. This allows components to receive continuous updates from external data channels (e.g., WebSocket streams, event emitters) while sharing subscription instances and efficiently managing resources.

The file exports a default hook, useSWRSubscription, which abstracts away the subscription lifecycle and integration with the SWR cache, providing a simple and declarative API for real-time data consumption in React applications.


Detailed Explanation

Key Concepts


Entities in the File

1. Type Alias: SubscriptionStates

type SubscriptionStates = [Map<string, number>, Map<string, () => void>]

2. Constant: subscriptionStorage

const subscriptionStorage = new WeakMap<object, SubscriptionStates>()

3. Constant: SUBSCRIPTION_PREFIX

const SUBSCRIPTION_PREFIX = '$sub$'

4. Middleware Function: subscription

export const subscription = (<Data = any, Error = any>(useSWRNext: SWRHook) =>
  (
    _key: Key,
    subscribe: SWRSubscription<any, Data, Error>,
    config: SWRConfiguration & typeof SWRConfig.defaultValue
  ): SWRSubscriptionResponse<Data, Error> => { ... }
) as unknown as Middleware

Purpose

Parameters

Return Value

Function Workflow

  1. Key Serialization and Prefixing
    The _key is serialized into [key, args]. The key is prefixed with SUBSCRIPTION_PREFIX to avoid cache conflicts.

  2. Initialize Subscription Storage
    If the subscriptionStorage does not have an entry for the specified cache, it initializes two maps—one for subscription counts, one for disposers.

  3. Retrieve Subscription State Maps
    Extracts the subscriptions map and disposers map for the current cache.

  4. Use Isomorphic Layout Effect
    A React hook (useIsomorphicLayoutEffect) runs on mount and unmount of components using the subscription:

    • On mount:

      • Increment the reference count for the subscription key.

      • If this is the first subscriber (refCount === 0), call the subscribe function with the arguments and a next callback.

      • Store the returned dispose function for later unsubscription.

    • On unmount:

      • Decrement the reference count.

      • If no subscribers remain (count === 0), call the dispose function to unsubscribe.

  5. next Callback for Data/Error Updates
    Passed to subscribe, it receives (error, data) from the external source and updates the SWR cache accordingly:

    • If an error is present, it sets the error in cache.

    • Otherwise, it clears the error and mutates the SWR cache with new data.

  6. Return Reactive Data and Error
    Returns an object with data and error getters that reflect the current SWR cache state.


5. Hook: useSWRSubscription

const useSWRSubscription = withMiddleware(
  useSWR,
  subscription
) as SWRSubscriptionHook

Purpose

Usage Example

import useSWRSubscription from 'swr/subscription'

const { data, error } = useSWRSubscription(key, (key, { next }) => {
  const unsubscribe = dataSource.subscribe(key, (err, data) => {
    next(err, data)
  })
  return unsubscribe
})

6. Exported Types

export type {
  SWRSubscription,
  SWRSubscriptionOptions,
  SWRSubscriptionResponse,
  SWRSubscriptionHook
}

Important Implementation Details


Interaction with Other Parts of the System


Mermaid Diagram: Subscription Middleware Class-Like Structure

classDiagram
    class SubscriptionMiddleware {
        -subscriptionStorage: WeakMap<object, SubscriptionStates>
        -SUBSCRIPTION_PREFIX: string = "$sub$"
        +subscription<Data, Error>(
            useSWRNext: SWRHook
          ) : (
            _key: Key,
            subscribe: SWRSubscription<any, Data, Error>,
            config: SWRConfiguration & typeof SWRConfig.defaultValue
          ) => SWRSubscriptionResponse<Data, Error>
    }

    class SWRSubscriptionHook {
        +useSWRSubscription<Key, Data, Error>(
            key: Key,
            subscribe: SWRSubscription<Key, Data, Error>,
            config?: SWRConfiguration
          ) : SWRSubscriptionResponse<Data, Error>
    }

    SubscriptionMiddleware ..> SWRSubscriptionHook : composes

Summary

index.ts provides the subscription middleware and hook that extend the SWR core functionality to support real-time data subscriptions with efficient resource management. The middleware manages multiple subscribers through reference counting, ensures cache isolation, and integrates subscription updates cleanly into the SWR state and React lifecycle. The exported useSWRSubscription hook exposes a simple API for components to declaratively receive live updates from external data sources, enabling seamless integration of reactive data streams into React applications.


Appendix: Usage Example

import useSWRSubscription from 'swr/subscription'

function MyComponent({ userId }) {
  const { data, error } = useSWRSubscription(
    userId,
    (id, { next }) => {
      // Subscribe to user data updates from an external data source
      const unsubscribe = userDataSource.subscribe(id, (err, userData) => {
        next(err, userData)
      })
      return unsubscribe
    },
    { refreshInterval: 0 } // optional SWR config
  )

  if (error) return <div>Error: {error.message}</div>
  if (!data) return <div>Loading...</div>

  return <div>User name: {data.name}</div>
}

This example demonstrates how a React component can subscribe to real-time user data updates using the useSWRSubscription hook.


End of Documentation for index.ts