# React Query integration

{% hint style="info" %}
For a working example of react-query integration, please take a look here

<https://github.com/rowsncolumns/spreadsheet/blob/main/examples/vite/spreadsheet-with-react-query.tsx>
{% endhint %}

For this example, lets try to sync \`sheets\` state with a back-end server using react query

## Installation

This document is based on React Query v3 - <https://tanstack.com/query/v3/docs/react/installation>

{% tabs %}
{% tab title="yarn" %}

```sh
yarn add @tanstack/react-query
```

{% endtab %}

{% tab title="npm" %}

```sh
npm i @tanstack/react-query
```

{% endtab %}
{% endtabs %}

## Create a Query Provider

Create a client and wrap the Spreadsheet with the provider

{% code overflow="wrap" %}

```typescript
import { QueryClient, QueryClientProvider, useQueryClient  } from "@tanstack/react-query"
import { Sheet, CanvasGrid } from "@rowsncolumns/spreadsheet"
import { Skeleton } from "@rowsncolumns/ui"
import { useSpreadsheetState } from "@rowsncolumns/spreadsheet-state"

const client = new QueryClient();
const initialSheets: Sheet[] = [{ title: "Sheet1", id: 1]

const Spreadsheet = () => {
  const queryClient = useQueryClient();
  // Initial sheets data
  const { data: sheets = [], isLoading } = useQuery<Sheet[]>(
    "sheets",
    () => fetch(`/api/sheets`).then((res) => res.json()),
    {
      initialData: initialSheets,
    }
  );
  
  // Mutating sheets
  const { mutate } = useMutation(
    (newSheets: Sheet[]) => {
      return fetch(`/api/sheets/`, {
        method: "POST",
        body: JSON.stringify(newSheets),
        headers: { "Content-Type": "application/json" },
      });
    },
    {
      async onMutate(newSheets) {
        await queryClient.cancelQueries({ queryKey: ["sheets"] });

        const previousSheets = queryClient.getQueryData(["sheets"]);

        // Optimistically update to the new value
        queryClient.setQueryData(["sheets"], newSheets);

        return {
          previousSheets,
        };
      },
      onError(err, _, context) {
        queryClient.setQueryData(["sheets"], context?.previousSheets);
      },
      // Always refetch after error or success:
      onSettled: () => {
        queryClient.invalidateQueries({ queryKey: ["sheets"] });
      },
    }
  );

  // Update sheets
  const onChangeSheets = useCallback<UseSpreadsheetProps["onChangeSheets"]>(
    (mayBeCallbackOrValue) => {
      const previousSheets =
        queryClient.getQueryData<Sheet[]>(["sheets"]) ?? [];

      mutate(
        typeof mayBeCallbackOrValue === "function"
          ? mayBeCallbackOrValue(previousSheets)
          : mayBeCallbackOrValue
      );
    },
    [mutate]
  );
  
  
  // Use Spreadsheet hook
  const { } = useSpreadsheetState({
    sheets,
    onChangeSheets
  })
  
  if (isLoading) {
    return (
      <div className="flex border-solid border-rnc-border border border-t border-b flex-1 justify-center items-center">
        <div className="space-y-2">
          <Skeleton className="h-4 w-[250px]" />
          <Skeleton className="h-4 w-[250px]" />
        </div>
      </div>
    )
  }
  
  return (
    <CanvasGrid
    />
  )
  
}

export const App = () => (
  <QueryClientProvider client={client}>
    <SpreadsheetProvider>
      <Spreadsheet />
    </SpreadsheetProvider>
  </QueryClientProvider>
)
```

{% endcode %}

This logic can be isolated to its own to synchronize `sheets` between client and server.

The same logic can be applied to `sheetData`


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://docs.rowsncolumns.app/data-persistence/react-query-integration.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
