Skip to content

fix(vue-query): Make queryKey watchers sync #5929

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
4 changes: 2 additions & 2 deletions examples/vue/dependent-queries/src/Post.vue
Original file line number Diff line number Diff line change
Expand Up @@ -36,9 +36,9 @@ export default defineComponent({

const { data: author } = useQuery(
['author', authorId],
() => fetchAuthor(authorId.value),
({ queryKey: [, id] }) => fetchAuthor(id),
{
enabled: computed(() => !!post.value?.userId),
enabled: computed(() => !!authorId.value),
},
)

Expand Down
49 changes: 36 additions & 13 deletions packages/vue-query/src/__tests__/useQuery.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -146,8 +146,6 @@ describe('useQuery', () => {
})

secondKeyRef.value = 'key8'
await flushPromises()

expect(query).toMatchObject({
status: { value: 'loading' },
data: { value: undefined },
Expand All @@ -172,9 +170,6 @@ describe('useQuery', () => {
})

enabled.value = true

await flushPromises()

expect(query).toMatchObject({
fetchStatus: { value: 'fetching' },
data: { value: undefined },
Expand All @@ -192,26 +187,26 @@ describe('useQuery', () => {

const enabled = computed(() => !!data.value)

const { fetchStatus, status } = useQuery(
const dependentQueryFn = jest.fn()
const { fetchStatus } = useQuery(
['dependant2'],
simpleFetcher,
dependentQueryFn,
reactive({
enabled,
}),
)

expect(data.value).toStrictEqual(undefined)
expect(fetchStatus.value).toStrictEqual('idle')
expect(dependentQueryFn).not.toHaveBeenCalled()

await flushPromises()

expect(data.value).toStrictEqual('Some data')
expect(fetchStatus.value).toStrictEqual('fetching')

await flushPromises()

expect(fetchStatus.value).toStrictEqual('idle')
expect(status.value).toStrictEqual('success')
expect(dependentQueryFn).toHaveBeenCalledTimes(1)
expect(dependentQueryFn).toHaveBeenCalledWith(
expect.objectContaining({ queryKey: ['dependant2'] }),
)
})

test('should stop listening to changes on onScopeDispose', async () => {
Expand All @@ -233,6 +228,34 @@ describe('useQuery', () => {
expect(status.value).toStrictEqual('loading')
})

test('should use the current value for the queryKey when refetch is called', async () => {
const fetchFn = jest.fn()
const keyRef = ref('key11')
const query = useQuery({
queryKey: ['key10', keyRef],
queryFn: fetchFn,
enabled: false,
})

expect(fetchFn).not.toHaveBeenCalled()
await query.refetch()
expect(fetchFn).toHaveBeenCalledTimes(1)
expect(fetchFn).toHaveBeenCalledWith(
expect.objectContaining({
queryKey: ['key10', 'key11'],
}),
)

keyRef.value = 'key12'
await query.refetch()
expect(fetchFn).toHaveBeenCalledTimes(2)
expect(fetchFn).toHaveBeenCalledWith(
expect.objectContaining({
queryKey: ['key10', 'key12'],
}),
)
})

describe('errorBoundary', () => {
test('should evaluate useErrorBoundary when query is expected to throw', async () => {
const boundaryFn = jest.fn()
Expand Down
12 changes: 8 additions & 4 deletions packages/vue-query/src/useBaseQuery.ts
Original file line number Diff line number Diff line change
Expand Up @@ -102,10 +102,14 @@ export function useBaseQuery<
{ immediate: true },
)

watch(defaultedOptions, () => {
observer.setOptions(defaultedOptions.value)
updateState(state, observer.getCurrentResult())
})
watch(
defaultedOptions,
() => {
observer.setOptions(defaultedOptions.value)
updateState(state, observer.getCurrentResult())
},
{ flush: 'sync' },
)

onScopeDispose(() => {
unsubscribe()
Expand Down
10 changes: 7 additions & 3 deletions packages/vue-query/src/useIsFetching.ts
Original file line number Diff line number Diff line change
Expand Up @@ -42,9 +42,13 @@ export function useIsFetching(
isFetching.value = queryClient.isFetching(filters)
})

watch(filters, () => {
isFetching.value = queryClient.isFetching(filters)
})
watch(
filters,
() => {
isFetching.value = queryClient.isFetching(filters)
},
{ flush: 'sync' },
)

onScopeDispose(() => {
unsubscribe()
Expand Down
10 changes: 7 additions & 3 deletions packages/vue-query/src/useIsMutating.ts
Original file line number Diff line number Diff line change
Expand Up @@ -42,9 +42,13 @@ export function useIsMutating(
isMutating.value = queryClient.isMutating(filters)
})

watch(filters, () => {
isMutating.value = queryClient.isMutating(filters)
})
watch(
filters,
() => {
isMutating.value = queryClient.isMutating(filters)
},
{ flush: 'sync' },
)

onScopeDispose(() => {
unsubscribe()
Expand Down
10 changes: 7 additions & 3 deletions packages/vue-query/src/useMutation.ts
Original file line number Diff line number Diff line change
Expand Up @@ -181,9 +181,13 @@ export function useMutation<
})
}

watch(options, () => {
observer.setOptions(queryClient.defaultMutationOptions(options.value))
})
watch(
options,
() => {
observer.setOptions(queryClient.defaultMutationOptions(options.value))
},
{ flush: 'sync' },
)

onScopeDispose(() => {
unsubscribe()
Expand Down
12 changes: 8 additions & 4 deletions packages/vue-query/src/useQueries.ts
Original file line number Diff line number Diff line change
Expand Up @@ -206,10 +206,14 @@ export function useQueries<T extends any[]>({
{ immediate: true },
)

watch(defaultedQueries, () => {
observer.setQueries(defaultedQueries.value)
state.splice(0, state.length, ...observer.getCurrentResult())
})
watch(
defaultedQueries,
() => {
observer.setQueries(defaultedQueries.value)
state.splice(0, state.length, ...observer.getCurrentResult())
},
{ flush: 'sync' },
)

onScopeDispose(() => {
unsubscribe()
Expand Down