React bindings to work with persisters in TanStack/react-query
npx @tessl/cli install tessl/npm-tanstack--react-query-persist-client@5.86.0TanStack React Query Persist Client provides React-specific bindings for persisting TanStack React Query client state and cache data. It exports a PersistQueryClientProvider component that wraps the standard QueryClientProvider to automatically restore persisted query data on application startup and continuously persist query state changes during runtime.
npm install @tanstack/react-query-persist-clientimport { PersistQueryClientProvider } from "@tanstack/react-query-persist-client";For CommonJS:
const { PersistQueryClientProvider } = require("@tanstack/react-query-persist-client");Core persistence utilities (re-exported from core package):
import {
persistQueryClient,
persistQueryClientRestore,
persistQueryClientSave,
persistQueryClientSubscribe,
experimental_createQueryPersister,
removeOldestQuery,
PERSISTER_KEY_PREFIX
} from "@tanstack/react-query-persist-client";Types and interfaces:
import type {
Persister,
PersistedClient,
PersistQueryClientOptions,
PersistedQueryClientRestoreOptions,
PersistedQueryClientSaveOptions,
PersistRetryer,
StoragePersisterOptions,
QueryPersister,
AsyncStorage,
PersistedQuery,
MaybePromise
} from "@tanstack/react-query-persist-client";import React from 'react';
import { QueryClient } from '@tanstack/react-query';
import { PersistQueryClientProvider } from '@tanstack/react-query-persist-client';
// Create a persister (example using localStorage)
const persister = {
persistClient: (client) => {
localStorage.setItem('queryClient', JSON.stringify(client));
},
restoreClient: () => {
const stored = localStorage.getItem('queryClient');
return stored ? JSON.parse(stored) : undefined;
},
removeClient: () => {
localStorage.removeItem('queryClient');
},
};
const queryClient = new QueryClient();
function App() {
return (
<PersistQueryClientProvider
client={queryClient}
persistOptions={{ persister }}
onSuccess={() => console.log('Cache restored!')}
onError={() => console.log('Failed to restore cache')}
>
<div>Your app components</div>
</PersistQueryClientProvider>
);
}The package is built around several key components:
React provider that manages persistence lifecycle, automatically restoring cache on mount and subscribing to changes for continuous persistence.
function PersistQueryClientProvider(props: PersistQueryClientProviderProps): React.JSX.Element;
interface PersistQueryClientProviderProps extends QueryClientProviderProps {
persistOptions: OmitKeyof<PersistQueryClientOptions, 'queryClient'>;
onSuccess?: () => Promise<unknown> | unknown;
onError?: () => Promise<unknown> | unknown;
}Low-level persistence functions for manual control over cache restoration, saving, and subscription management.
function persistQueryClient(props: PersistQueryClientOptions): [() => void, Promise<void>];
function persistQueryClientRestore(options: PersistedQueryClientRestoreOptions): Promise<void>;
function persistQueryClientSave(options: PersistedQueryClientSaveOptions): Promise<void>;
function persistQueryClientSubscribe(props: PersistedQueryClientSaveOptions): () => void;Abstract interface for implementing custom storage solutions, with support for various storage backends.
interface Persister {
persistClient: (persistClient: PersistedClient) => Promisable<void>;
restoreClient: () => Promisable<PersistedClient | undefined>;
removeClient: () => Promisable<void>;
}
interface PersistedClient {
timestamp: number;
buster: string;
clientState: DehydratedState;
}Experimental fine-grained persistence functionality that allows per-query persistence control and storage management.
function experimental_createQueryPersister<TStorageValue = string>(
options: StoragePersisterOptions<TStorageValue>
): QueryPersister;Built-in retry strategies for handling persistence failures and storage quota issues.
type PersistRetryer = (props: {
persistedClient: PersistedClient;
error: Error;
errorCount: number;
}) => PersistedClient | undefined;
function removeOldestQuery(props: {
persistedClient: PersistedClient;
error: Error;
errorCount: number;
}): PersistedClient | undefined;type Promisable<T> = T | PromiseLike<T>;
interface PersistQueryClientOptions extends
PersistedQueryClientRestoreOptions,
PersistedQueryClientSaveOptions,
PersistQueryClientRootOptions {}
interface PersistQueryClientRootOptions {
queryClient: QueryClient;
persister: Persister;
buster?: string;
}
interface PersistedQueryClientRestoreOptions extends PersistQueryClientRootOptions {
maxAge?: number;
hydrateOptions?: HydrateOptions;
}
interface PersistedQueryClientSaveOptions extends PersistQueryClientRootOptions {
dehydrateOptions?: DehydrateOptions;
}
// Core TanStack Query types (from @tanstack/query-core)
interface QueryClient {
// QueryClient interface - core query management
}
interface DehydratedState {
mutations: Array<any>;
queries: Array<any>;
}
interface HydrateOptions {
// Options for hydrating dehydrated state
shouldDehydrateQuery?: (query: any) => boolean;
shouldDehydrateMutation?: (mutation: any) => boolean;
}
interface DehydrateOptions {
// Options for dehydrating state for persistence
shouldDehydrateQuery?: (query: any) => boolean;
shouldDehydrateMutation?: (mutation: any) => boolean;
}
interface QueryClientProviderProps {
client: QueryClient;
children: React.ReactNode;
}
type OmitKeyof<T, K extends keyof T> = Omit<T, K>;
// Constants
const PERSISTER_KEY_PREFIX = 'tanstack-query';