Links

React Query integration

React-query is a first-class library to manage asynchronous states
For a working example of react-query integration, please take a look here
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
yarn
npm
yarn add @tanstack/react-query
npm i @tanstack/react-query

Create a Query Provider

Create a client and wrap the Spreadsheet with the provider
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>
)
This logic can be isolated to its own to synchronize sheets between client and server.
The same logic can be applied to sheetData