Middleware Composition
Purpose
Middleware Composition addresses the challenge of extending the core SWR data fetching hook with additional functionality in a modular and reusable manner. Rather than embedding features directly into the core hook, this subtopic provides a utility to layer multiple middleware functions, allowing developers to compose complex behaviors (e.g., logging, caching strategies, subscription handling) seamlessly on top of the base SWR hook. This promotes clean separation of concerns, easier maintenance, and flexible customization of hook behavior without modifying core logic.
Functionality
At its core, Middleware Composition enables wrapping the original useSWR hook with one or more middleware functions that can intercept and enhance the hook’s inputs, outputs, or internal lifecycle.
Input normalization: The composition utility first normalizes the arguments passed to the hook, ensuring uniform handling regardless of how the user calls it.
Middleware chaining: It appends the new middleware to any existing middleware array specified in the configuration, preserving previously applied layers.
Hook invocation: The composed hook then calls the original
useSWRwith the modified middleware stack, enabling middleware to inject or modify behaviors such as caching, preloading, or subscriptions.
This pattern supports recursive or nested middleware composition, enabling complex feature layering while maintaining a simple interface for consumers.
Key Code Interaction
The withMiddleware function is the centerpiece:
export const withMiddleware = (
useSWR: SWRHook,
middleware: Middleware
): SWRHook => {
return <Data = any, Error = any>(...args) => {
const [key, fn, config] = normalize(args)
const uses = (config.use || []).concat(middleware)
return useSWR<Data, Error>(key, fn, { ...config, use: uses })
}
}
normalize(args)standardizes the input parameters.The new middleware is concatenated to the existing
usearray in the configuration.The original
useSWRis invoked with the enhanced config, triggering the middleware chain during data fetching.
Integration
Middleware Composition is the foundational utility that enables the broader Middleware Architecture within the project. By providing a consistent way to layer middleware, it allows all other middleware features—such as preloading, devtools integration, subscription management, and immutable data handling—to plug into the core SWR hook transparently.
Other subtopics like Built-in Middlewares rely on this composition utility to bundle multiple middleware layers.
It complements the Core Data Fetching hook by extending its capabilities without altering its fundamental implementation.
Middleware layers applied through this composition can coordinate with cache providers, event emitters, and React’s lifecycle, ensuring consistent state and side effect management.
This mechanism empowers developers to create custom middleware or combine existing ones, fostering an extensible and scalable data fetching ecosystem.
Diagram
sequenceDiagram
participant Component as React Component
participant ComposedHook as Composed SWR Hook
participant MiddlewareChain as Middleware Stack
participant CoreHook as Core useSWR Hook
Component->>ComposedHook: Call with args (key, fetcher, config)
ComposedHook->>ComposedHook: Normalize args
ComposedHook->>MiddlewareChain: Append new middleware to config.use
ComposedHook->>CoreHook: Invoke useSWR with updated config
CoreHook->>MiddlewareChain: Execute middleware chain during hook lifecycle
MiddlewareChain->>CoreHook: Enhance fetch/data behavior
CoreHook-->>ComposedHook: Return SWR state and utilities
ComposedHook-->>Component: Provide SWR data and methods
This sequence illustrates how a React component calls a SWR hook wrapped with middleware composition, which normalizes inputs, extends middleware, and delegates to the core hook. The middleware chain then augments the hook’s behavior before returning stateful data to the component.