SWR re-renders the whole paginated data array when optimisticData and data functions return an array
Author: tandetatCreated Nov 13, 2025Updated Aug 1, 2026
Bug report
Description / Observed Behavior
When using mutate() with both optimisticData and an async data function that return structurally identical data (but different references), SWR triggers two renders even though the data content is the same. This causes mutations to paginated data to re-render the whole array twice.
Observed in useSWRInfinite:
const { data, mutate } = useSWRInfinite(getKey, fetcher);
// This causes TWO renders even if server returns identical data
mutate(
async (current) => {
const result = await api.addItem(item);
return [...result]; // New reference #1
},
{
optimisticData: (current) => [...current, item], // New reference #2
revalidate: false
}
);Result:
- First render with optimisticData array
- Second render with final data array (even though contents are identical)
Expected Behavior
SWR should use compare() function in mutation paths. When the final data from a mutation is structurally identical to the current cached data (including optimistic data), SWR should return the existing reference to avoid a cache update and match the revalidation.
Repro Steps / Code Example
import useSWRInfinite from 'swr/infinite';
function MyComponent() {
const { data, mutate } = useSWRInfinite(
(index) => `/api/items?page=${index}`,
fetcher
);
const addItem = async (item: Item) => {
// BUG: This causes two renders even if API returns the same item
await mutate(
async (currentPages) => {
const newItem = await fetch('/api/items', {
method: 'POST',
body: JSON.stringify(item)
}).then(r => r.json());
// Optimistic item and server item have same content
// but different references
return currentPages.map((page, i) =>
i === 0
? [newItem, ...page] // New reference
: page
);
},
{
optimisticData: (currentPages) =>
currentPages.map((page, i) =>
i === 0
? [item, ...page] // New reference
: page
),
revalidate: false
}
);
};
// Renders twice even though optimistic and final data are identical
return <div>{data?.[0]?.length} items</div>;
}Additional Context
SWR version: 2.3.6
Source: vercel/swr