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
44 changes: 23 additions & 21 deletions packages/query-core/src/queryObserver.ts
Original file line number Diff line number Diff line change
Expand Up @@ -594,27 +594,7 @@ export class QueryObserver<
promise: this.#currentThenable,
}

return result as QueryObserverResult<TData, TError>
}

updateResult(notifyOptions?: NotifyOptions): void {
const prevResult = this.#currentResult as
| QueryObserverResult<TData, TError>
| undefined

const nextResult = this.createResult(this.#currentQuery, this.options)

this.#currentResultState = this.#currentQuery.state
this.#currentResultOptions = this.options

if (this.#currentResultState.data !== undefined) {
this.#lastQueryWithDefinedData = this.#currentQuery
}

// Only notify and update result if something has changed
if (shallowEqualObjects(nextResult, prevResult)) {
return
}
const nextResult = result as QueryObserverResult<TData, TError>

if (this.options.experimental_prefetchInRender) {
const finalizeThenableIfPossible = (thenable: PendingThenable<TData>) => {
Expand Down Expand Up @@ -662,6 +642,28 @@ export class QueryObserver<
}
}

return nextResult
}

updateResult(notifyOptions?: NotifyOptions): void {
const prevResult = this.#currentResult as
| QueryObserverResult<TData, TError>
| undefined

const nextResult = this.createResult(this.#currentQuery, this.options)

this.#currentResultState = this.#currentQuery.state
this.#currentResultOptions = this.options

if (this.#currentResultState.data !== undefined) {
this.#lastQueryWithDefinedData = this.#currentQuery
}

// Only notify and update result if something has changed
if (shallowEqualObjects(nextResult, prevResult)) {
return
}

this.#currentResult = nextResult

// Determine which callbacks to trigger
Expand Down
14 changes: 13 additions & 1 deletion packages/react-query/src/__tests__/useMutationState.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,19 @@ describe('useIsMutating', () => {
fireEvent.click(rendered.getByRole('button', { name: /mutate1/i }))
await sleep(10)
fireEvent.click(rendered.getByRole('button', { name: /mutate2/i }))
await waitFor(() => expect(isMutatingArray).toEqual([0, 1, 2, 1, 0]))

// we don't really care if this yields
// [ +0, 1, 2, +0 ]
// or
// [ +0, 1, 2, 1, +0 ]
// our batching strategy might yield different results

await waitFor(() => expect(isMutatingArray[0]).toEqual(0))
await waitFor(() => expect(isMutatingArray[1]).toEqual(1))
await waitFor(() => expect(isMutatingArray[2]).toEqual(2))
await waitFor(() =>
expect(isMutatingArray[isMutatingArray.length - 1]).toEqual(0),
)
})

it('should filter correctly by mutationKey', async () => {
Expand Down
87 changes: 87 additions & 0 deletions packages/react-query/src/__tests__/useQuery.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -7385,5 +7385,92 @@ describe('useQuery', () => {
fireEvent.click(rendered.getByText('enable'))
await waitFor(() => rendered.getByText('test1'))
})

it('should show correct data when read from cache only (staleTime)', async () => {
const key = queryKey()
let suspenseRenderCount = 0
queryClient.setQueryData(key, 'initial')

function MyComponent(props: { promise: Promise<string> }) {
const data = React.use(props.promise)

return <>{data}</>
}

function Loading() {
suspenseRenderCount++
return <>loading..</>
}
function Page() {
const query = useQuery({
queryKey: key,
queryFn: async () => {
await sleep(1)
return 'test'
},
staleTime: Infinity,
})

return (
<React.Suspense fallback={<Loading />}>
<MyComponent promise={query.promise} />
</React.Suspense>
)
}

const rendered = renderWithClient(queryClient, <Page />)
await waitFor(() => rendered.getByText('initial'))

expect(suspenseRenderCount).toBe(0)
})

it('should show correct data when switching between cache entries without re-fetches', async () => {
const key = queryKey()

function MyComponent(props: { promise: Promise<string> }) {
const data = React.use(props.promise)

return <>{data}</>
}

function Loading() {
return <>loading..</>
}
function Page() {
const [count, setCount] = React.useState(0)
const query = useQuery({
queryKey: [key, count],
queryFn: async () => {
await sleep(10)
return 'test' + count
},
staleTime: Infinity,
})

return (
<div>
<React.Suspense fallback={<Loading />}>
<MyComponent promise={query.promise} />
</React.Suspense>
<button onClick={() => setCount(count + 1)}>inc</button>
<button onClick={() => setCount(count - 1)}>dec</button>
</div>
)
}

const rendered = renderWithClient(queryClient, <Page />)
await waitFor(() => rendered.getByText('loading..'))
await waitFor(() => rendered.getByText('test0'))

fireEvent.click(rendered.getByText('inc'))
await waitFor(() => rendered.getByText('loading..'))

await waitFor(() => rendered.getByText('test1'))

console.log('---------dec------------')
fireEvent.click(rendered.getByText('dec'))

await waitFor(() => rendered.getByText('test0'))
})
})
})
7 changes: 2 additions & 5 deletions packages/vue-query/src/useMutationState.ts
Original file line number Diff line number Diff line change
Expand Up @@ -71,12 +71,9 @@ export function useMutationState<TResult = MutationState>(
): Readonly<Ref<Array<TResult>>> {
const filters = computed(() => cloneDeepUnref(options.filters))
const mutationCache = (queryClient || useQueryClient()).getMutationCache()
const state = shallowRef(getResult(mutationCache, options)) as Ref<
Array<TResult>
>
const state = shallowRef(getResult(mutationCache, options))
const unsubscribe = mutationCache.subscribe(() => {
const result = getResult(mutationCache, options)
state.value = result
state.value = getResult(mutationCache, options)
})

watch(filters, () => {
Expand Down
Loading