Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions docs/framework/react/plugins/persistQueryClient.md
Original file line number Diff line number Diff line change
Expand Up @@ -219,6 +219,10 @@ ReactDOM.createRoot(rootElement).render(
- will be called when the initial restore is finished
- can be used to [resumePausedMutations](../../../reference/QueryClient.md#queryclientresumepausedmutations)
- if a Promise is returned, it will be awaited; restoring is seen as ongoing until then
- `onError?: () => Promise<unknown> | unknown`
- optional
- will be called when an error is thrown during restoration
- if a Promise is returned, it will be awaited

### useIsRestoring

Expand Down
4 changes: 2 additions & 2 deletions examples/react/basic/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -9,10 +9,10 @@
"test:eslint": "eslint ./src"
},
"dependencies": {
"@tanstack/query-sync-storage-persister": "^5.72.2",
"@tanstack/query-sync-storage-persister": "^5.73.1",
"@tanstack/react-query": "^5.72.2",
"@tanstack/react-query-devtools": "^5.72.2",
"@tanstack/react-query-persist-client": "^5.72.2",
"@tanstack/react-query-persist-client": "^5.73.1",
"react": "^19.0.0",
"react-dom": "^19.0.0"
},
Expand Down
4 changes: 2 additions & 2 deletions examples/react/eslint-legacy/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -9,10 +9,10 @@
"test:eslint": "eslint ./src"
},
"dependencies": {
"@tanstack/query-sync-storage-persister": "^5.72.2",
"@tanstack/query-sync-storage-persister": "^5.73.1",
"@tanstack/react-query": "^5.72.2",
"@tanstack/react-query-devtools": "^5.72.2",
"@tanstack/react-query-persist-client": "^5.72.2",
"@tanstack/react-query-persist-client": "^5.73.1",
"react": "^19.0.0",
"react-dom": "^19.0.0"
},
Expand Down
4 changes: 2 additions & 2 deletions examples/react/offline/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -8,11 +8,11 @@
"preview": "vite preview"
},
"dependencies": {
"@tanstack/query-sync-storage-persister": "^5.72.2",
"@tanstack/query-sync-storage-persister": "^5.73.1",
"@tanstack/react-location": "^3.7.4",
"@tanstack/react-query": "^5.72.2",
"@tanstack/react-query-devtools": "^5.72.2",
"@tanstack/react-query-persist-client": "^5.72.2",
"@tanstack/react-query-persist-client": "^5.73.1",
"msw": "^2.6.6",
"react": "^19.0.0",
"react-dom": "^19.0.0",
Expand Down
4 changes: 2 additions & 2 deletions examples/svelte/basic/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -8,10 +8,10 @@
"preview": "vite preview"
},
"dependencies": {
"@tanstack/query-sync-storage-persister": "^5.72.2",
"@tanstack/query-sync-storage-persister": "^5.73.1",
"@tanstack/svelte-query": "^5.72.2",
"@tanstack/svelte-query-devtools": "^5.72.2",
"@tanstack/svelte-query-persist-client": "^5.72.2"
"@tanstack/svelte-query-persist-client": "^5.73.1"
},
"devDependencies": {
"@sveltejs/adapter-auto": "^3.3.1",
Expand Down
2 changes: 1 addition & 1 deletion examples/vue/2.6-basic/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
"_preview": "vite preview"
},
"dependencies": {
"@tanstack/vue-query": "^5.72.2",
"@tanstack/vue-query": "^5.73.0",
"@vue/composition-api": "1.7.2",
"vue": "2.6.14",
"vue-template-compiler": "2.6.14"
Expand Down
2 changes: 1 addition & 1 deletion examples/vue/2.7-basic/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
"_serve": "vite preview"
},
"dependencies": {
"@tanstack/vue-query": "^5.72.2",
"@tanstack/vue-query": "^5.73.0",
"vue": "2.7.16",
"vue-template-compiler": "2.7.16"
},
Expand Down
4 changes: 2 additions & 2 deletions examples/vue/basic/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,8 @@
"preview": "vite preview"
},
"dependencies": {
"@tanstack/vue-query": "^5.72.2",
"@tanstack/vue-query-devtools": "^5.72.2",
"@tanstack/vue-query": "^5.73.0",
"@tanstack/vue-query-devtools": "^5.73.0",
"vue": "^3.4.27"
},
"devDependencies": {
Expand Down
2 changes: 1 addition & 1 deletion examples/vue/dependent-queries/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
"preview": "vite preview"
},
"dependencies": {
"@tanstack/vue-query": "^5.72.2",
"@tanstack/vue-query": "^5.73.0",
"vue": "^3.4.27"
},
"devDependencies": {
Expand Down
2 changes: 1 addition & 1 deletion examples/vue/nuxt3/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
"_start": "node .output/server/index.mjs"
},
"dependencies": {
"@tanstack/vue-query": "^5.72.2"
"@tanstack/vue-query": "^5.73.0"
},
"devDependencies": {
"nuxt": "^3.12.4"
Expand Down
6 changes: 3 additions & 3 deletions examples/vue/persister/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -9,9 +9,9 @@
},
"dependencies": {
"@tanstack/query-core": "^5.72.2",
"@tanstack/query-persist-client-core": "^5.72.2",
"@tanstack/query-sync-storage-persister": "^5.72.2",
"@tanstack/vue-query": "^5.72.2",
"@tanstack/query-persist-client-core": "^5.73.1",
"@tanstack/query-sync-storage-persister": "^5.73.1",
"@tanstack/vue-query": "^5.73.0",
"idb-keyval": "^6.2.1",
"vue": "^3.4.27"
},
Expand Down
4 changes: 2 additions & 2 deletions examples/vue/simple/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,8 @@
"preview": "vite preview"
},
"dependencies": {
"@tanstack/vue-query": "^5.72.2",
"@tanstack/vue-query-devtools": "^5.72.2",
"@tanstack/vue-query": "^5.73.0",
"@tanstack/vue-query-devtools": "^5.73.0",
"vue": "^3.4.27"
},
"devDependencies": {
Expand Down
2 changes: 1 addition & 1 deletion packages/query-async-storage-persister/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@tanstack/query-async-storage-persister",
"version": "5.72.2",
"version": "5.73.1",
"description": "A persister for asynchronous storages, to be used with TanStack/Query",
"author": "tannerlinsley",
"license": "MIT",
Expand Down
2 changes: 1 addition & 1 deletion packages/query-persist-client-core/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@tanstack/query-persist-client-core",
"version": "5.72.2",
"version": "5.73.1",
"description": "Set of utilities for interacting with persisters, which can save your queryClient for later use",
"author": "tannerlinsley",
"license": "MIT",
Expand Down
99 changes: 98 additions & 1 deletion packages/query-persist-client-core/src/__tests__/persist.test.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,9 @@
import { describe, expect, test, vi } from 'vitest'
import { QueriesObserver } from '@tanstack/query-core'
import { persistQueryClientSubscribe } from '../persist'
import {
persistQueryClientRestore,
persistQueryClientSubscribe,
} from '../persist'
import {
createMockPersister,
createQueryClient,
Expand Down Expand Up @@ -63,3 +66,97 @@ describe('persistQueryClientSave', () => {
unsubscribe()
})
})

describe('persistQueryClientRestore', () => {
test('should rethrow exceptions in `restoreClient`', async () => {
const consoleMock = vi
.spyOn(console, 'error')
.mockImplementation(() => undefined)

const consoleWarn = vi
.spyOn(console, 'warn')
.mockImplementation(() => undefined)

const queryClient = createQueryClient()

const restoreError = new Error('Error restoring client')

const persister = createSpyPersister()

persister.restoreClient = () => Promise.reject(restoreError)

await expect(
persistQueryClientRestore({
queryClient,
persister,
}),
).rejects.toBe(restoreError)

expect(consoleMock).toHaveBeenCalledTimes(1)
expect(consoleWarn).toHaveBeenCalledTimes(1)
expect(consoleMock).toHaveBeenNthCalledWith(1, restoreError)

consoleMock.mockRestore()
consoleWarn.mockRestore()
})

test('should rethrow exceptions in `removeClient` before `restoreClient`', async () => {
const consoleMock = vi
.spyOn(console, 'error')
.mockImplementation(() => undefined)

const consoleWarn = vi
.spyOn(console, 'warn')
.mockImplementation(() => undefined)

const queryClient = createQueryClient()

const restoreError = new Error('Error restoring client')
const removeError = new Error('Error removing client')

const persister = createSpyPersister()

persister.restoreClient = () => Promise.reject(restoreError)
persister.removeClient = () => Promise.reject(removeError)

await expect(
persistQueryClientRestore({
queryClient,
persister,
}),
).rejects.toBe(removeError)

expect(consoleMock).toHaveBeenCalledTimes(1)
expect(consoleWarn).toHaveBeenCalledTimes(1)
expect(consoleMock).toHaveBeenNthCalledWith(1, restoreError)

consoleMock.mockRestore()
consoleWarn.mockRestore()
})

test('should rethrow error in `removeClient`', async () => {
const queryClient = createQueryClient()

const persister = createSpyPersister()
const removeError = new Error('Error removing client')

persister.removeClient = () => Promise.reject(removeError)
persister.restoreClient = () => {
return Promise.resolve({
buster: 'random-buster',
clientState: {
mutations: [],
queries: [],
},
timestamp: new Date().getTime(),
})
}

await expect(
persistQueryClientRestore({
queryClient,
persister,
}),
).rejects.toBe(removeError)
})
})
9 changes: 6 additions & 3 deletions packages/query-persist-client-core/src/persist.ts
Original file line number Diff line number Diff line change
Expand Up @@ -84,12 +84,12 @@ export async function persistQueryClientRestore({
const expired = Date.now() - persistedClient.timestamp > maxAge
const busted = persistedClient.buster !== buster
if (expired || busted) {
persister.removeClient()
return persister.removeClient()
} else {
hydrate(queryClient, persistedClient.clientState, hydrateOptions)
}
} else {
persister.removeClient()
return persister.removeClient()
}
}
} catch (err) {
Expand All @@ -99,7 +99,10 @@ export async function persistQueryClientRestore({
'Encountered an error attempting to restore client cache from persisted location. As a precaution, the persisted cache will be discarded.',
)
}
persister.removeClient()

await persister.removeClient()

throw err
}
}

Expand Down
2 changes: 1 addition & 1 deletion packages/query-sync-storage-persister/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@tanstack/query-sync-storage-persister",
"version": "5.72.2",
"version": "5.73.1",
"description": "A persister for synchronous storages, to be used with TanStack/Query",
"author": "tannerlinsley",
"license": "MIT",
Expand Down
2 changes: 1 addition & 1 deletion packages/react-query-persist-client/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@tanstack/react-query-persist-client",
"version": "5.72.2",
"version": "5.73.1",
"description": "React bindings to work with persisters in TanStack/react-query",
"author": "tannerlinsley",
"license": "MIT",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,20 +12,22 @@ import type { OmitKeyof, QueryClientProviderProps } from '@tanstack/react-query'
export type PersistQueryClientProviderProps = QueryClientProviderProps & {
persistOptions: OmitKeyof<PersistQueryClientOptions, 'queryClient'>
onSuccess?: () => Promise<unknown> | unknown
onError?: () => Promise<unknown> | unknown
}

export const PersistQueryClientProvider = ({
children,
persistOptions,
onSuccess,
onError,
...props
}: PersistQueryClientProviderProps): React.JSX.Element => {
const [isRestoring, setIsRestoring] = React.useState(true)
const refs = React.useRef({ persistOptions, onSuccess })
const refs = React.useRef({ persistOptions, onSuccess, onError })
const didRestore = React.useRef(false)

React.useEffect(() => {
refs.current = { persistOptions, onSuccess }
refs.current = { persistOptions, onSuccess, onError }
})

React.useEffect(() => {
Expand All @@ -35,13 +37,12 @@ export const PersistQueryClientProvider = ({
}
if (!didRestore.current) {
didRestore.current = true
persistQueryClientRestore(options).then(async () => {
try {
await refs.current.onSuccess?.()
} finally {
persistQueryClientRestore(options)
.then(() => refs.current.onSuccess?.())
.catch(() => refs.current.onError?.())
.finally(() => {
setIsRestoring(false)
}
})
})
}
return isRestoring ? undefined : persistQueryClientSubscribe(options)
}, [props.client, isRestoring])
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -539,6 +539,8 @@ describe('PersistQueryClientProvider', () => {

const queryClient = createQueryClient()
const removeClient = vi.fn()
const onSuccess = vi.fn()
const onError = vi.fn()

const [error, persister] = createMockErrorPersister(removeClient)

Expand All @@ -563,13 +565,18 @@ describe('PersistQueryClientProvider', () => {
<PersistQueryClientProvider
client={queryClient}
persistOptions={{ persister }}
onSuccess={onSuccess}
onError={onError}
>
<Page />
</PersistQueryClientProvider>,
)

await waitFor(() => rendered.getByText('fetched'))
expect(removeClient).toHaveBeenCalledTimes(1)
expect(onSuccess).toHaveBeenCalledTimes(0)
expect(onError).toHaveBeenCalledTimes(1)

expect(consoleMock).toHaveBeenCalledTimes(1)
expect(consoleMock).toHaveBeenNthCalledWith(1, error)
consoleMock.mockRestore()
Expand Down
2 changes: 1 addition & 1 deletion packages/solid-query-persist-client/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@tanstack/solid-query-persist-client",
"version": "5.72.2",
"version": "5.73.1",
"description": "Solid.js bindings to work with persisters in TanStack/solid-query",
"author": "tannerlinsley",
"license": "MIT",
Expand Down
Loading
Loading