gridcn1.2.2
RecipesData fetching

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.