useUpdateMany is a modified version of TanStack Query’s useMutation for multiple update mutations.
It uses the updateMany method from the dataProvider. If the dataProvider doesn’t have an updateMany method, it will call update for each item individually.
Usage
import { useUpdateMany } from "@refinedev/core" ;
interface IProduct {
id : number ;
name : string ;
price : number ;
isActive : boolean ;
}
const { mutate } = useUpdateMany < IProduct >();
mutate ({
resource: "products" ,
ids: [ 1 , 2 , 3 ],
values: {
isActive: true ,
},
});
Parameters
You can pass parameters either to the hook or to the mutate/mutateAsync functions. Parameters passed to the mutation functions override those passed to the hook.
Resource name for API data interactions.
Array of record IDs to update.
Values for the mutation function - the data to update.
mutationMode
'pessimistic' | 'optimistic' | 'undoable'
Duration in ms to wait before executing the mutation when mutationMode = "undoable".
onCancel
(cancelMutation: () => void) => void
Provides a function to cancel the mutation when mutationMode = "undoable".
Meta data for the dataProvider. Can be used to pass additional parameters to data provider methods.
If there is more than one dataProvider, you should specify which one to use.
invalidates
Array<keyof IQueryKeys>
default: "['list', 'many']"
Specify which queries should be invalidated after successful mutation. Options: 'list', 'many', 'detail', 'resourceAll', 'all'.
optimisticUpdateMap
OptimisticUpdateManyMapType<TData, TVariables>
You can use it to manage optimistic updates for different query types. list
boolean | function
default: "true"
Enable optimistic updates for list queries or provide a custom updater function
many
boolean | function
default: "true"
Enable optimistic updates for many queries or provide a custom updater function
detail
boolean | function
default: "true"
Enable optimistic updates for detail queries or provide a custom updater function
successNotification
OpenNotificationParams | false | ((data, values) => OpenNotificationParams | false)
Success notification configuration. Set to false to disable.
errorNotification
OpenNotificationParams | false | ((error, values) => OpenNotificationParams | false)
Error notification configuration. Set to false to disable.
TanStack Query’s useMutation options. onSuccess
(data, variables, context) => void
Callback function called on successful mutation
onError
(error, variables, context) => void
Callback function called on failed mutation
onSettled
(data, error, variables, context) => void
Callback function called after mutation completes (success or error)
overtimeOptions
UseLoadingOvertimeOptionsProps
Configuration for loading overtime behavior.
Return Values
mutate
(params?: UseUpdateManyParams) => void
Function to trigger the mutation.
mutateAsync
(params?: UseUpdateManyParams) => Promise<UpdateManyResponse<TData>>
Async version that returns a promise.
TanStack Query’s useMutation return object. data
UpdateManyResponse<TData>
The response data from the mutation
Loading state of the mutation
Error object if the mutation failed
Loading overtime information. Elapsed time in milliseconds
Examples
Basic Usage
import { useUpdateMany } from "@refinedev/core" ;
const { mutate } = useUpdateMany ();
const handleUpdate = ( ids : number [], values : Partial < IProduct >) => {
mutate ({
resource: "products" ,
ids ,
values ,
});
};
Bulk Status Update
import { useUpdateMany } from "@refinedev/core" ;
const BulkActions = ({ selectedIds } : { selectedIds : number [] }) => {
const { mutate } = useUpdateMany ();
const activateProducts = () => {
mutate ({
resource: "products" ,
ids: selectedIds ,
values: { isActive: true },
});
};
const deactivateProducts = () => {
mutate ({
resource: "products" ,
ids: selectedIds ,
values: { isActive: false },
});
};
return (
< div >
< button onClick = { activateProducts } > Activate Selected </ button >
< button onClick = { deactivateProducts } > Deactivate Selected </ button >
</ div >
);
};
With Optimistic Updates
const { mutate } = useUpdateMany ({
mutationMode: "optimistic" ,
});
mutate ({
resource: "products" ,
ids: [ 1 , 2 , 3 ],
values: { isActive: true },
});
With Undoable Mode
const { mutate } = useUpdateMany ({
mutationMode: "undoable" ,
undoableTimeout: 5000 , // 5 seconds to undo
});
mutate ({
resource: "products" ,
ids: [ 1 , 2 , 3 ],
values: { isActive: true },
onCancel : ( cancelMutation ) => {
// Provide cancel button in your UI
document . getElementById ( "undoBtn" )?. addEventListener ( "click" , cancelMutation );
},
});
With Async/Await
const { mutateAsync } = useUpdateMany ();
const handleBulkUpdate = async ( ids : number [], values : Partial < IProduct >) => {
try {
const result = await mutateAsync ({
resource: "products" ,
ids ,
values ,
});
console . log ( "Updated products:" , result . data );
} catch ( error ) {
console . error ( "Failed to update products:" , error );
}
};
With Callbacks
const { mutate } = useUpdateMany ({
mutationOptions: {
onSuccess : ( data ) => {
console . log ( "Updated products:" , data . data );
},
onError : ( error ) => {
console . error ( "Error:" , error . message );
},
},
});
mutate ({
resource: "products" ,
ids: [ 1 , 2 , 3 ],
values: { isActive: true },
});
Custom Optimistic Update
const { mutate } = useUpdateMany ({
optimisticUpdateMap: {
list : ( previous , values , ids ) => {
if ( ! previous ) return null ;
return {
... previous ,
data: previous . data . map (( item ) =>
ids . includes ( item . id )
? { ... item , ... values , updatedAt: new Date (). toISOString () }
: item
),
};
},
},
});
Disable Notifications
const { mutate } = useUpdateMany ({
successNotification: false ,
errorNotification: false ,
});
const { mutate } = useUpdateMany ();
mutate ({
resource: "products" ,
ids: [ 1 , 2 , 3 ],
values: { isActive: true },
meta: {
headers: { "X-Custom-Header" : "value" },
},
});
Type Parameters
TData - Result data type of the mutation. Extends BaseRecord.
TError - Custom error type that extends HttpError.
TVariables - Type of the values/payload for the mutation.
FAQ
What happens if dataProvider doesn't have updateMany?
If the dataProvider doesn’t implement the updateMany method, Refine will automatically fall back to calling the update method for each ID individually.
pessimistic (default): UI updates after server confirms
optimistic: UI updates immediately, rolls back on error
undoable: UI updates immediately with option to undo before server request
Learn more about mutation modes
Can I prevent automatic query invalidation?
Yes, set invalidates to an empty array: mutate ({
resource: "products" ,
ids: [ 1 , 2 , 3 ],
values: { isActive: true },
invalidates: [],
});