Skip to main content
useMany is a modified version of TanStack Query’s useQuery for retrieving multiple records by their IDs from a resource. It uses the getMany method from the dataProvider if available, or falls back to multiple getOne calls.

Usage

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

interface IProduct {
  id: number;
  name: string;
  price: number;
}

const products = useMany<IProduct>({
  resource: "products",
  ids: [1, 2, 3, 4, 5],
});

Parameters

resource
string
required
Resource name for API data interactions.
ids
BaseKey[]
required
Array of record IDs to fetch. Each ID can be a string or number.
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.
queryOptions
UseQueryOptions
TanStack Query’s useQuery options.
successNotification
OpenNotificationParams | false | ((data, ids) => OpenNotificationParams | false)
Success notification configuration. Set to false to disable.
errorNotification
OpenNotificationParams | false | ((error, ids) => OpenNotificationParams | false)
Error notification configuration. Set to false to disable.
liveMode
'auto' | 'manual' | 'off'
Live/Realtime mode configuration.
onLiveEvent
(event) => void
Callback to handle live events.
liveParams
object
Additional parameters for live queries.
overtimeOptions
UseLoadingOvertimeOptionsProps
Configuration for loading overtime behavior.

Return Values

result
object
Simplified result object.
query
QueryObserverResult
TanStack Query’s useQuery return object.
overtime
object
Loading overtime information.

Examples

Basic Usage

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

const { result, query } = useMany({
  resource: "products",
  ids: [1, 2, 3],
});

const products = result.data;
// [{ id: 1, name: "Product 1" }, { id: 2, name: "Product 2" }, ...]

With Dynamic IDs

const [selectedIds, setSelectedIds] = useState<number[]>([]);

const { result } = useMany({
  resource: "products",
  ids: selectedIds,
  queryOptions: {
    enabled: selectedIds.length > 0,
  },
});
import { useList, useMany } from "@refinedev/core";

// First, get a list of orders
const { result: ordersResult } = useList({
  resource: "orders",
});

// Extract unique product IDs from orders
const productIds = [
  ...new Set(ordersResult.data.map((order) => order.productId)),
];

// Fetch all related products
const { result: productsResult } = useMany({
  resource: "products",
  ids: productIds,
  queryOptions: {
    enabled: productIds.length > 0,
  },
});

With Meta Data

const { result } = useMany({
  resource: "products",
  ids: [1, 2, 3],
  meta: {
    fields: ["id", "name", "price"],
  },
});

With Data Transformation

const { result } = useMany({
  resource: "products",
  ids: [1, 2, 3],
  queryOptions: {
    select: (data) => ({
      ...data,
      data: data.data.map((product) => ({
        ...product,
        displayName: `${product.name} - $${product.price}`,
      })),
    }),
  },
});

Creating a Lookup Map

const { result } = useMany({
  resource: "categories",
  ids: [1, 2, 3],
});

// Create a lookup map for efficient access
const categoryMap = result.data.reduce((acc, category) => {
  acc[category.id] = category;
  return acc;
}, {} as Record<number, ICategory>);

// Now you can quickly look up categories by ID
const category = categoryMap[1];

Handling Empty IDs

const { result, query } = useMany({
  resource: "products",
  ids: selectedIds,
  queryOptions: {
    enabled: selectedIds.length > 0,
  },
});

if (selectedIds.length === 0) {
  return <div>No products selected</div>;
}

if (query.isLoading) {
  return <div>Loading...</div>;
}

return (
  <ul>
    {result.data.map((product) => (
      <li key={product.id}>{product.name}</li>
    ))}
  </ul>
);

Type Parameters

  • TQueryFnData - Result data type returned by the query function. Extends BaseRecord.
  • TError - Custom error type that extends HttpError.
  • TData - Result data type returned by the select function. Extends BaseRecord. Defaults to TQueryFnData.

FAQ

If the getMany method is not implemented in your data provider, Refine will automatically fall back to making multiple getOne requests in parallel.
Use the queryOptions.enabled parameter:
const { result } = useMany({
  resource: "products",
  ids: selectedIds,
  queryOptions: {
    enabled: selectedIds.length > 0,
  },
});
The order depends on your data provider implementation. Most data providers will return results in the same order as the requested IDs, but this is not guaranteed by Refine.
useMany is much more efficient as it makes a single API request (if your data provider supports getMany). Using multiple useOne calls would create multiple separate queries and API requests.

Build docs developers (and LLMs) love