diff --git a/packages/svelte-query/src/__tests__/CreateQuery.svelte b/packages/svelte-query/src/__tests__/CreateQuery.svelte
index 6e12574d16..b0a833bbff 100644
--- a/packages/svelte-query/src/__tests__/CreateQuery.svelte
+++ b/packages/svelte-query/src/__tests__/CreateQuery.svelte
@@ -1,17 +1,18 @@
{#if $query.isLoading}
@@ -21,3 +22,9 @@
{:else if $query.isSuccess}
Success
{/if}
+
+
+ {#each $query.data ?? [] as entry}
+ - id: {entry.id}
+ {/each}
+
diff --git a/packages/svelte-query/src/__tests__/createQuery.test.ts b/packages/svelte-query/src/__tests__/createQuery.test.ts
index 191fea1b23..9e07929298 100644
--- a/packages/svelte-query/src/__tests__/createQuery.test.ts
+++ b/packages/svelte-query/src/__tests__/createQuery.test.ts
@@ -1,16 +1,20 @@
import { describe, it, expect } from 'vitest'
import { render, screen } from '@testing-library/svelte'
+import { writable } from 'svelte/store'
import CreateQuery from './CreateQuery.svelte'
import { sleep } from './utils'
+import type { CreateQueryOptions, WritableOrVal } from '../types'
describe('createQuery', () => {
it('Render and wait for success', async () => {
render(CreateQuery, {
props: {
- queryKey: ['test'],
- queryFn: async () => {
- await sleep(100)
- return 'Success'
+ options: {
+ queryKey: ['test'],
+ queryFn: async () => {
+ await sleep(100)
+ return 'Success'
+ },
},
},
})
@@ -25,4 +29,38 @@ describe('createQuery', () => {
expect(screen.queryByText('Loading')).not.toBeInTheDocument()
expect(screen.queryByText('Error')).not.toBeInTheDocument()
})
+
+ it('should keep previous data with keepPreviousData option set to true', async () => {
+ const options: WritableOrVal = writable({
+ queryKey: ['test', [1]],
+ queryFn: async ({ queryKey }) => {
+ await sleep(100)
+ const ids = queryKey[1]
+ if (!ids || !Array.isArray(ids)) return []
+ return ids.map((id) => ({ id }))
+ },
+ keepPreviousData: true,
+ })
+ render(CreateQuery, { props: { options } })
+
+ expect(screen.queryByText('id: 1')).not.toBeInTheDocument()
+ expect(screen.queryByText('id: 2')).not.toBeInTheDocument()
+
+ await sleep(200)
+
+ expect(screen.queryByText('id: 1')).toBeInTheDocument()
+ expect(screen.queryByText('id: 2')).not.toBeInTheDocument()
+
+ options.update((o) => ({ ...o, queryKey: ['test', [1, 2]] }))
+
+ await sleep(0)
+
+ expect(screen.queryByText('id: 1')).toBeInTheDocument()
+ expect(screen.queryByText('id: 2')).not.toBeInTheDocument()
+
+ await sleep(200)
+
+ expect(screen.queryByText('id: 1')).toBeInTheDocument()
+ expect(screen.queryByText('id: 2')).toBeInTheDocument()
+ })
})
diff --git a/packages/svelte-query/src/createBaseQuery.ts b/packages/svelte-query/src/createBaseQuery.ts
index 401dfc51e2..8ed4bdfa3d 100644
--- a/packages/svelte-query/src/createBaseQuery.ts
+++ b/packages/svelte-query/src/createBaseQuery.ts
@@ -3,9 +3,19 @@ import {
type QueryKey,
type QueryObserver,
} from '@tanstack/query-core'
-import type { CreateBaseQueryOptions, CreateBaseQueryResult } from './types'
+import { derived, readable, writable, get, type Writable } from 'svelte/store'
+import type {
+ CreateBaseQueryOptions,
+ CreateBaseQueryResult,
+ WritableOrVal,
+} from './types'
import { useQueryClient } from './useQueryClient'
-import { derived, readable } from 'svelte/store'
+
+function isWritable(
+ obj: WritableOrVal,
+): obj is Writable {
+ return 'subscribe' in obj
+}
export function createBaseQuery<
TQueryFnData,
@@ -14,51 +24,60 @@ export function createBaseQuery<
TQueryData,
TQueryKey extends QueryKey,
>(
- options: CreateBaseQueryOptions<
- TQueryFnData,
- TError,
- TData,
- TQueryData,
- TQueryKey
+ options: WritableOrVal<
+ CreateBaseQueryOptions
>,
Observer: typeof QueryObserver,
): CreateBaseQueryResult {
const queryClient = useQueryClient()
- const defaultedOptions = queryClient.defaultQueryOptions(options)
- defaultedOptions._optimisticResults = 'optimistic'
- let observer = new Observer<
+ let optionsStore: Writable<
+ CreateBaseQueryOptions
+ >
+ if (isWritable(options)) {
+ optionsStore = options
+ } else {
+ optionsStore = writable(options)
+ }
+
+ const defaultedOptionsStore = derived(optionsStore, ($options) => {
+ const defaultedOptions = queryClient.defaultQueryOptions($options)
+ defaultedOptions._optimisticResults = 'optimistic'
+
+ // Include callbacks in batch renders
+ if (defaultedOptions.onError) {
+ defaultedOptions.onError = notifyManager.batchCalls(
+ defaultedOptions.onError,
+ )
+ }
+
+ if (defaultedOptions.onSuccess) {
+ defaultedOptions.onSuccess = notifyManager.batchCalls(
+ defaultedOptions.onSuccess,
+ )
+ }
+
+ if (defaultedOptions.onSettled) {
+ defaultedOptions.onSettled = notifyManager.batchCalls(
+ defaultedOptions.onSettled,
+ )
+ }
+
+ return defaultedOptions
+ })
+
+ const observer = new Observer<
TQueryFnData,
TError,
TData,
TQueryData,
TQueryKey
- >(queryClient, defaultedOptions)
-
- // Include callbacks in batch renders
- if (defaultedOptions.onError) {
- defaultedOptions.onError = notifyManager.batchCalls(
- defaultedOptions.onError,
- )
- }
-
- if (defaultedOptions.onSuccess) {
- defaultedOptions.onSuccess = notifyManager.batchCalls(
- defaultedOptions.onSuccess,
- )
- }
-
- if (defaultedOptions.onSettled) {
- defaultedOptions.onSettled = notifyManager.batchCalls(
- defaultedOptions.onSettled,
- )
- }
+ >(queryClient, get(defaultedOptionsStore))
- readable(observer).subscribe(($observer) => {
- observer = $observer
+ defaultedOptionsStore.subscribe(($defaultedOptions) => {
// Do not notify on updates because of changes in the options because
// these changes should already be reflected in the optimistic result.
- observer.setOptions(defaultedOptions, { listeners: false })
+ observer.setOptions($defaultedOptions, { listeners: false })
})
const result = readable(observer.getCurrentResult(), (set) => {
@@ -66,8 +85,8 @@ export function createBaseQuery<
})
const { subscribe } = derived(result, ($result) => {
- $result = observer.getOptimisticResult(defaultedOptions)
- return !defaultedOptions.notifyOnChangeProps
+ $result = observer.getOptimisticResult(get(defaultedOptionsStore))
+ return !get(defaultedOptionsStore).notifyOnChangeProps
? observer.trackResult($result)
: $result
})
diff --git a/packages/svelte-query/src/createQuery.ts b/packages/svelte-query/src/createQuery.ts
index da26283b20..9025383be2 100644
--- a/packages/svelte-query/src/createQuery.ts
+++ b/packages/svelte-query/src/createQuery.ts
@@ -5,6 +5,7 @@ import type {
DefinedCreateQueryResult,
CreateQueryOptions,
CreateQueryResult,
+ WritableOrVal,
} from './types'
export function createQuery<
@@ -14,7 +15,7 @@ export function createQuery<
TQueryKey extends QueryKey = QueryKey,
>(
options: Omit<
- CreateQueryOptions,
+ WritableOrVal>,
'initialData'
> & {
initialData?: () => undefined
@@ -28,7 +29,7 @@ export function createQuery<
TQueryKey extends QueryKey = QueryKey,
>(
options: Omit<
- CreateQueryOptions,
+ WritableOrVal>,
'initialData'
> & {
initialData: TQueryFnData | (() => TQueryFnData)
@@ -41,7 +42,9 @@ export function createQuery<
TData = TQueryFnData,
TQueryKey extends QueryKey = QueryKey,
>(
- options: CreateQueryOptions,
+ options: WritableOrVal<
+ CreateQueryOptions
+ >,
): CreateQueryResult
export function createQuery<
@@ -52,7 +55,7 @@ export function createQuery<
>(
queryKey: TQueryKey,
options?: Omit<
- CreateQueryOptions,
+ WritableOrVal>,
'queryKey' | 'initialData'
> & { initialData?: () => undefined },
): CreateQueryResult
@@ -65,7 +68,7 @@ export function createQuery<
>(
queryKey: TQueryKey,
options?: Omit<
- CreateQueryOptions,
+ WritableOrVal>,
'queryKey' | 'initialData'
> & { initialData: TQueryFnData | (() => TQueryFnData) },
): DefinedCreateQueryResult
@@ -78,7 +81,7 @@ export function createQuery<
>(
queryKey: TQueryKey,
options?: Omit<
- CreateQueryOptions,
+ WritableOrVal>,
'queryKey'
>,
): CreateQueryResult
@@ -92,7 +95,7 @@ export function createQuery<
queryKey: TQueryKey,
queryFn: QueryFunction,
options?: Omit<
- CreateQueryOptions,
+ WritableOrVal>,
'queryKey' | 'queryFn' | 'initialData'
> & { initialData?: () => undefined },
): CreateQueryResult
@@ -106,7 +109,7 @@ export function createQuery<
queryKey: TQueryKey,
queryFn: QueryFunction,
options?: Omit<
- CreateQueryOptions,
+ WritableOrVal>,
'queryKey' | 'queryFn' | 'initialData'
> & { initialData: TQueryFnData | (() => TQueryFnData) },
): DefinedCreateQueryResult
@@ -120,7 +123,7 @@ export function createQuery<
queryKey: TQueryKey,
queryFn: QueryFunction,
options?: Omit<
- CreateQueryOptions,
+ WritableOrVal>,
'queryKey' | 'queryFn'
>,
): CreateQueryResult
@@ -131,13 +134,25 @@ export function createQuery<
TData = TQueryFnData,
TQueryKey extends QueryKey = QueryKey,
>(
- arg1: TQueryKey | CreateQueryOptions,
+ arg1:
+ | TQueryKey
+ | WritableOrVal>,
arg2?:
| QueryFunction
- | CreateQueryOptions,
- arg3?: CreateQueryOptions,
+ | WritableOrVal>,
+ arg3?: WritableOrVal<
+ CreateQueryOptions
+ >,
): CreateQueryResult {
- const parsedOptions = parseQueryArgs(arg1, arg2, arg3)
+ const parsedOptions = parseQueryArgs(
+ arg1 as
+ | TQueryKey
+ | CreateQueryOptions,
+ arg2 as
+ | QueryFunction
+ | CreateQueryOptions,
+ arg3 as CreateQueryOptions,
+ )
const result = createBaseQuery(parsedOptions, QueryObserver)
return result
}
diff --git a/packages/svelte-query/src/types.ts b/packages/svelte-query/src/types.ts
index 853f6c464b..65d9081060 100644
--- a/packages/svelte-query/src/types.ts
+++ b/packages/svelte-query/src/types.ts
@@ -10,7 +10,9 @@ import type {
DefinedQueryObserverResult,
} from '@tanstack/query-core'
import type { QueryClient } from '@tanstack/query-core'
-import type { Readable } from 'svelte/store'
+import type { Readable, Writable } from 'svelte/store'
+
+export type WritableOrVal = T | Writable
export interface ContextOptions {
/**