Skip to main content
useDelete is a modified version of TanStack Query’s useMutation for delete mutations. It uses the deleteOne method from the dataProvider and supports optimistic updates, pessimistic updates, and undoable mutations.

Usage

import { useDelete } from "@refinedev/core";

const { mutate } = useDelete();

mutate({
  resource: "products",
  id: 1,
});

Parameters

Parameters are passed to the mutate/mutateAsync functions.
resource
string
required
Resource name for API data interactions.
id
BaseKey
required
ID of the record to delete. Can be a string or number.
mutationMode
'pessimistic' | 'optimistic' | 'undoable'
Determines when mutations are executed. Defaults to the global mutation mode.
  • pessimistic: Deletion is applied after the server responds
  • optimistic: Deletion is applied immediately, rolled back on error
  • undoable: Deletion is applied immediately with an option to undo
undoableTimeout
number
default:"5000"
Duration in milliseconds to wait before executing the mutation when mutationMode is undoable.
onCancel
(cancelMutation: () => void) => void
Callback that provides a function to cancel the mutation when mutationMode is undoable.
meta
MetaQuery
Meta data for the dataProvider. Can be used to pass additional parameters to data provider methods.
dataProviderName
string
default:"default"
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'.
values
TVariables
Additional values to pass to the delete mutation (rarely used).
successNotification
OpenNotificationParams | false | ((data, id) => OpenNotificationParams | false)
Success notification configuration. Set to false to disable.
errorNotification
OpenNotificationParams | false | ((error, id) => OpenNotificationParams | false)
Error notification configuration. Set to false to disable.

Hook Options

mutationOptions
UseMutationOptions
TanStack Query’s useMutation options (excluding mutationFn, onMutate, onSuccess, onError, onSettled).
overtimeOptions
UseLoadingOvertimeOptionsProps
Configuration for loading overtime behavior.

Return Values

mutate
(params: DeleteParams) => void
Function to trigger the mutation.
mutateAsync
(params: DeleteParams) => Promise<DeleteOneResponse<TData>>
Async version that returns a promise.
mutation
UseMutationResult
TanStack Query’s useMutation return object.
overtime
object
Loading overtime information.

Examples

Basic Usage

import { useDelete } from "@refinedev/core";

const { mutate } = useDelete();

const handleDelete = (id: number) => {
  mutate({
    resource: "products",
    id,
  });
};

With Confirmation

import { useDelete } from "@refinedev/core";

const { mutate } = useDelete();

const handleDelete = (id: number) => {
  if (window.confirm("Are you sure you want to delete this product?")) {
    mutate({
      resource: "products",
      id,
    });
  }
};

With Async/Await

const { mutateAsync } = useDelete();

const handleDelete = async (id: number) => {
  try {
    await mutateAsync({
      resource: "products",
      id,
    });
    console.log("Product deleted successfully");
  } catch (error) {
    console.error("Failed to delete:", error);
  }
};

Optimistic Deletion

import { useDelete } from "@refinedev/core";

const { mutate } = useDelete();

mutate({
  resource: "products",
  id: 1,
  mutationMode: "optimistic",
});
// Item is removed from UI immediately, restored on error

Undoable Deletion

import { useDelete } from "@refinedev/core";
import { notification } from "antd";

const { mutate } = useDelete();

const handleDelete = (id: number) => {
  mutate({
    resource: "products",
    id,
    mutationMode: "undoable",
    undoableTimeout: 5000,
    onCancel: (cancelMutation) => {
      notification.open({
        key: `delete-${id}`,
        message: "Deleting product...",
        description: "You have 5 seconds to undo",
        btn: (
          <button onClick={cancelMutation}>
            Undo
          </button>
        ),
        duration: 5,
      });
    },
  });
};

With Loading State

const { mutate, mutation } = useDelete();

return (
  <button
    onClick={() => mutate({ resource: "products", id: 1 })}
    disabled={mutation.isPending}
  >
    {mutation.isPending ? "Deleting..." : "Delete"}
  </button>
);

With Success Callback

import { useDelete } from "@refinedev/core";
import { useNavigate } from "react-router-dom";

const navigate = useNavigate();

const { mutate } = useDelete();

mutate(
  {
    resource: "products",
    id: 1,
  },
  {
    onSuccess: () => {
      navigate("/products");
    },
  }
);

Disable Notifications

const { mutate } = useDelete();

mutate({
  resource: "products",
  id: 1,
  successNotification: false,
  errorNotification: false,
});

Custom Notifications

const { mutate } = useDelete();

mutate({
  resource: "products",
  id: 1,
  successNotification: (data, id) => ({
    message: `Product #${id} deleted`,
    description: "Success",
    type: "success",
  }),
  errorNotification: (error, id) => ({
    message: `Failed to delete product #${id}`,
    description: error.message,
    type: "error",
  }),
});

Custom Invalidation

const { mutate } = useDelete();

mutate({
  resource: "products",
  id: 1,
  invalidates: ["list", "many", "detail"],
});

With Meta Data

const { mutate } = useDelete();

mutate({
  resource: "products",
  id: 1,
  meta: {
    headers: { "X-Custom-Header": "value" },
  },
});

Soft Delete

import { useUpdate } from "@refinedev/core";

// Instead of using useDelete, use useUpdate to mark as deleted
const { mutate: softDelete } = useUpdate();

softDelete({
  resource: "products",
  id: 1,
  values: {
    deletedAt: new Date().toISOString(),
    status: "deleted",
  },
});

Type Parameters

  • TData - Result data type of the mutation. Extends BaseRecord.
  • TError - Custom error type that extends HttpError.
  • TVariables - Type of additional variables/payload for the mutation.

FAQ

  • Pessimistic: Removes from UI only after server confirms deletion (safest)
  • Optimistic: Removes from UI immediately, restores on error (best UX)
  • Undoable: Removes from UI immediately with option to cancel (Gmail-style)
Use useUpdate instead of useDelete to mark records as deleted:
const { mutate } = useUpdate();

mutate({
  resource: "products",
  id: 1,
  values: { deleted: true },
});
Yes, use the values parameter:
mutate({
  resource: "products",
  id: 1,
  values: {
    reason: "Out of stock",
  },
});
Use Refine’s useModalForm or wrap the mutate call:
const handleDelete = (id: number) => {
  if (window.confirm("Are you sure?")) {
    mutate({ resource: "products", id });
  }
};
By default, useDelete invalidates list and many queries for the resource. Detail queries for the specific ID are removed from the cache.

Build docs developers (and LLMs) love