README.md mutationDefaults.ts
queryClient.ts
QueryClientProvider.ts
storagePersister.ts
These files demonstrates how to persist queries and mutations to offline state with the following behaviour:
- Serve from query cache if offline
- Persist mutations if offline, and resume mutations once online
It's important to set the online manager state before rendering the <QueryClientProvider />
, for example:
<NetworkStateProvider><QueryClientProvider>{children}</QueryClientProvider></NetworkStateProvider>
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import type { QueryClient } from '@tanstack/react-query'; | |
import { fetchSubmitForm, useSubmitForm } from './your/api'; | |
import { DEFAULT_RETRIES } from './constants'; | |
export function setMutationDefaults(queryClient: QueryClient) { | |
queryClient.setMutationDefaults([useSubmitForm.name], { | |
mutationFn: fetchSubmitForm, | |
retry: DEFAULT_RETRIES, | |
}); | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import { MutationCache, QueryCache, QueryClient } from '@tanstack/react-query'; | |
import { setMutationDefaults } from './mutationDefaults'; | |
export const queryClient = new QueryClient({ | |
queryCache: new QueryCache(), | |
mutationCache: new MutationCache(), | |
defaultOptions: { | |
queries: { | |
refetchOnWindowFocus: false, | |
staleTime: 0, // always refresh if online | |
cacheTime: Infinity, // cache forever | |
}, | |
mutations: { | |
cacheTime: Infinity, // cache forever | |
}, | |
}, | |
}); | |
setMutationDefaults(queryClient); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import React, { type PropsWithChildren } from 'react'; | |
import { PersistQueryClientProvider } from '@tanstack/react-query-persist-client'; | |
import { onlineManager } from '@tanstack/react-query'; | |
import { queryClient } from './queryClient'; | |
import { storagePersister } from './storagePersister'; | |
export function QueryClientProvider(props: PropsWithChildren) { | |
return ( | |
<PersistQueryClientProvider | |
client={queryClient} | |
persistOptions={{ persister: storagePersister }} | |
onSuccess={async () => { | |
if (onlineManager.isOnline()) { | |
await queryClient.resumePausedMutations(); | |
await queryClient.invalidateQueries(); | |
} | |
}} | |
{...props} | |
/> | |
); | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import { createSyncStoragePersister } from '@tanstack/query-sync-storage-persister'; | |
import { MMKV } from 'react-native-mmkv'; | |
const storage = new MMKV(); | |
const clientStorage = { | |
setItem: (key: string, value: string) => { | |
storage.set(key, value); | |
}, | |
getItem: (key: string) => { | |
const value = storage.getString(key); | |
return value === undefined ? null : value; | |
}, | |
removeItem: (key: string) => { | |
storage.delete(key); | |
}, | |
}; | |
export const storagePersister = createSyncStoragePersister({ | |
storage: clientStorage, | |
}); |