TanStack Query wiring
Wire onDataChange to useQuery and useMutation with an optimistic cache update.
Grid-side parts are the contract. TanStack Query parts are illustrative
gridcn does not install @tanstack/react-query. The snippet is written against its stable
public API (useQuery/useMutation/onMutate/onError), the same illustrative-snippet
convention as the Standard Schema example in
Editing & cell types. See also
Lazy loading: data fetching & failure recovery
for the same rule applied to data-grid-lazy.
useQuery fetches the rows, and one useMutation handles every operation from onDataChange, keyed
off the same queryKey so its cache and the grid stay in sync:
"use client";
function OrdersGrid() {
const queryClient = useQueryClient();
const ordersQuery = useQuery({ queryKey: ["orders"], queryFn: api.orders.list });
const mutation = useMutation({
mutationFn: (change: DataChange<Order>) => Promise.all(opsToRequests(change.ops)),
onMutate: async (change) => {
await queryClient.cancelQueries({ queryKey: ["orders"] });
const previous = queryClient.getQueryData<Order[]>(["orders"]);
queryClient.setQueryData<Order[]>(["orders"], (rows) => applyChange(rows ?? [], change, (row) => row.id));
return { previous };
},
onError: (_error, _change, context) => {
if (context?.previous) queryClient.setQueryData(["orders"], context.previous);
toast.error("Could not save your change. It has been reverted.");
},
onSettled: () => {
queryClient.invalidateQueries({ queryKey: ["orders"] });
},
});
return (
<DataGrid
data={ordersQuery.data ?? []}
columns={columns}
onDataChange={(_next, change) => mutation.mutate(change)}
/>
);
}applyChange is the core's operation engine, exported from the data-grid barrel. It applies the
whole batch in one pass: row-id-based updates and deletes, inserts at their snapshot positions,
missing row ids skipped. The onMutate/onError pair is the same optimistic-vs-rollback shape
as Strategy A, expressed through TanStack Query's
cache.
For a socket or poll that pushes new values many times per second, write them with updateCells
instead of a new data array. See Streaming updates.