index.ts
Overview
This file implements the core of remote data mutation functionality within the SWR ecosystem. It defines a React hook useSWRMutation that allows components to perform manual, controlled remote mutations such as POST, PUT, DELETE, and PATCH requests. The hook handles mutation state tracking (data, error, isMutating), concurrency control to avoid race conditions, cache synchronization with SWR’s global cache, and configurable mutation behavior including optimistic updates and error handling.
The mutation logic is encapsulated as a middleware that wraps the core useSWR hook, maintaining consistency with SWR’s architecture and enabling extensibility. This file exports the hook as the default export along with relevant mutation-related types.
Detailed Explanation
Mutation Middleware Function: mutation
This is the core middleware function that adds mutation capabilities on top of the useSWR hook.
const mutation = (<Data, Error>() =>
(
key: Key,
fetcher: MutationFetcher<Data>,
config: SWRMutationConfiguration<Data, Error> = {}
) => { ... }
) as unknown as Middleware
Parameters
key: Key
A unique identifier for the resource to mutate. Should match keys used in SWR's cache for consistency.fetcher: MutationFetcher<Data>
A function that performs the remote mutation. It receives the resolved key and an options object containing the mutation argument (arg). It returns the mutation result or throws an error.config: SWRMutationConfiguration<Data, Error>(optional)
Configuration options controlling mutation behavior including cache updates, error handling, and callbacks.
Internal State and Refs
keyRef,fetcherRef,configRef
React refs to always hold the latestkey,fetcher, andconfigvalues without triggering re-renders.ditchMutationsUntilRef
A timestamp ref to track mutation start times. Mutations started before this timestamp are discarded to avoid race conditions.stateRef,stateDependencies,setState
State hook with dependency tracking holding mutation state:data: mutation result data orundefinederror: error occurred during mutation orundefinedisMutating: boolean flag indicating if a mutation is in progress
trigger Function
const trigger = useCallback(
async (arg: any, opts?: SWRMutationConfiguration<Data, Error>) => { ... },
[]
)
Purpose: Manually triggers the mutation.
Parameters:
arg: The argument passed to the fetcher function (often mutation payload).opts: Optional override configuration for this specific mutation trigger.
Behavior:
Serializes the key to ensure valid cache keys.
Validates presence of fetcher and key; throws if missing.
Merges default config (
populateCache: false,throwOnError: true), global config, andopts.Records mutation start timestamp and updates
ditchMutationsUntilRef.Sets
isMutatingtotrue.Calls SWR’s
mutateto perform the mutation, updating cache accordingly.On success: updates
data, clearserror, setsisMutatingtofalse, and callsonSuccesscallback.On error: updates
error, clears loading flag, callsonErrorcallback, and optionally rethrows error.Ignores any mutation results that are stale based on timestamp.
Returns: The mutation result data on success, or throws an error if configured.
Usage Example:
const { data, error, isMutating, trigger, reset } = useSWRMutation(
'/api/user',
async (url, { arg }) => {
const response = await fetch(url, {
method: 'POST',
body: JSON.stringify(arg)
})
if (!response.ok) throw new Error('Failed to mutate')
return await response.json()
}
)
const onSubmit = async (formData) => {
try {
const result = await trigger(formData)
console.log('Mutation result:', result)
} catch (e) {
console.error('Mutation error:', e)
}
}
reset Function
const reset = useCallback(() => {
ditchMutationsUntilRef.current = getTimestamp()
setState({ data: UNDEFINED, error: UNDEFINED, isMutating: false })
}, [])
Resets mutation state to initial values, clearing any data or error and marking
isMutatingas false.Updates the timestamp to ignore any ongoing mutations that started before reset.
State Accessors
The returned object provides getters for data, error, and isMutating properties that also track which part of state is consumed to optimize component re-renders.
useSWRMutation Hook
const useSWRMutation = withMiddleware(
useSWR,
mutation
) as unknown as SWRMutationHook
Composes the mutation middleware with the core
useSWRhook usingwithMiddleware.Provides the final hook interface for external use.
This hook exposes the mutation API:
{ data, error, isMutating, trigger, reset }.
Exported Types
The file exports mutation-related types to assist developers in typing mutation fetchers, configuration, and response objects:
SWRMutationConfigurationSWRMutationResponseSWRMutationHookMutationFetcherTriggerWithArgsTriggerWithoutArgsTriggerWithOptionsArgs
These types define the contract for mutation usage, enabling strong typing and better DX.
Important Implementation Details
Timestamp-Based Mutation Discarding:
To avoid race conditions when multiple mutations overlap, each mutation records a timestamp (mutationStartedAt). State updates from mutations that started earlier than the latest timestamp are discarded, preventing stale results from overriding fresh ones.State Management with Dependency Tracking:
Uses a customuseStateWithDepshook to track which state properties are accessed by consumers, resulting in optimized re-renders only when relevant mutation state changes.Cache Integration:
Mutation triggers SWR'smutateinternally to update the SWR cache atomically and trigger revalidation if necessary.Configurable Options:
Default behavior disables cache population (populateCache: false) and enables error throwing (throwOnError: true), but these can be overridden per mutation call. Callback hooksonSuccessandonErrorallow side effects.React Concurrent Features:
Uses React'sstartTransitionto update state with lower priority, improving UI responsiveness during mutation state changes.No Direct Exposure of
mutate:
The SWRmutatefunction is not exposed to consumers of this hook to avoid confusion and enforce usage oftriggerwhich manages mutation state properly.
Interaction with Other System Parts
useSWRCore Hook:
Mutation is implemented as middleware wrappinguseSWR, leveraging its cache and revalidation capabilities.SWR Global Cache Context (
useSWRConfig):
Accessesmutatefrom SWR's global configuration to orchestrate cache updates.State Utilities:
UsesuseStateWithDepsandstartTransitionfrom the internalstatemodule for efficient state handling.Utilities:
serializeconverts keys to serialized strings for cache indexing.mergeObjectsmerges options objects.getTimestampprovides monotonic timestamps for mutation ordering.useIsomorphicLayoutEffectsynchronizes refs with latest props.
Exports and External Usage:
Other parts of the application or libraries importuseSWRMutationto perform mutations, enabling consistent remote state changes with UI feedback.
Visual Diagram
classDiagram
class MutationMiddleware {
+trigger(arg: any, opts?: SWRMutationConfiguration): Promise<Data | undefined>
+reset(): void
+data: Data | undefined
+error: Error | undefined
+isMutating: boolean
}
class useSWRMutation {
+trigger(arg: any, opts?: SWRMutationConfiguration): Promise<Data | undefined>
+reset(): void
+data: Data | undefined
+error: Error | undefined
+isMutating: boolean
}
useSWRMutation --|> MutationMiddleware
Summary
The index.ts file implements the useSWRMutation hook, a powerful and flexible React hook to perform remote mutations integrated with SWR's caching and revalidation system. It provides:
Manual mutation triggering with arguments and options
Fine-grained mutation state tracking (
data,error,isMutating)Concurrency control using timestamps to avoid stale updates
Cache synchronization with SWR's global cache
Configurable mutation behavior including optimistic updates and callbacks
Efficient state management to minimize re-renders
This hook enables developers to easily perform remote mutations in React applications while maintaining UI consistency and responsiveness, fitting cleanly into the SWR ecosystem’s modular middleware architecture.