Skip to content
Closed
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
72 changes: 72 additions & 0 deletions packages/solid-query/src/__tests__/suspense.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -951,4 +951,76 @@ describe("useQuery's in Suspense mode", () => {
expect(renders).toBe(2)
expect(rendered.queryByText('rendered')).toBeInTheDocument()
})

it('should not trigger suspense when setQueryData is called with pre-cached data and refetchOnMount: false', async () => {
const key = queryKey()
let suspenseCount = 0

const localQueryClient = new QueryClient({
defaultOptions: {
queries: {
refetchOnMount: false,
},
},
})

localQueryClient.setQueryData(key, { likes: 42 })

function Loading() {
suspenseCount++
return <div>loading</div>
}

function Example() {
const query = useQuery(() => ({
queryKey: key,
queryFn: () => Promise.resolve({ likes: 42 }),
}))

const mutate = () => {
const old = localQueryClient.getQueryData(key) as { likes: number }
localQueryClient.setQueryData(key, {
...old,
likes: old.likes + 1,
})
}

return (
<div>
<span data-testid="likes">{query.data?.likes}</span>
<button data-testid="mutate" onClick={mutate}>
mutate
</button>
</div>
)
}

const rendered = render(() => (
<QueryClientProvider client={localQueryClient}>
<Suspense fallback={<Loading />}>
<Example />
</Suspense>
</QueryClientProvider>
))

await vi.advanceTimersByTimeAsync(0)

// Initial render should show cached data without triggering suspense
expect(rendered.getByTestId('likes').textContent).toBe('42')
expect(suspenseCount).toBe(0)

// First mutation
fireEvent.click(rendered.getByTestId('mutate'))
await vi.advanceTimersByTimeAsync(0)
expect(rendered.getByTestId('likes').textContent).toBe('43')
expect(suspenseCount).toBe(0)

// Second mutation
fireEvent.click(rendered.getByTestId('mutate'))
await vi.advanceTimersByTimeAsync(0)
expect(rendered.getByTestId('likes').textContent).toBe('44')

// Suspense should never trigger when data is already cached
expect(suspenseCount).toBe(0)
})
})
14 changes: 11 additions & 3 deletions packages/solid-query/src/useBaseQuery.ts
Original file line number Diff line number Diff line change
Expand Up @@ -260,7 +260,8 @@ export function useBaseQuery<
setStateWithReconciliation(observerResult)
return reject(observerResult.error)
}
if (!observerResult.isLoading) {
// eslint-disable-next-line @typescript-eslint/no-unnecessary-condition -- data can be undefined at runtime despite type inference
if (!observerResult.isLoading || observerResult.data !== undefined) {
resolver = null
return resolve(
hydratableObserverResult(obs.getCurrentQuery(), observerResult),
Expand Down Expand Up @@ -376,9 +377,16 @@ export function useBaseQuery<
prop: keyof QueryObserverResult<TData, TError>,
): any {
if (prop === 'data') {
if (state.data !== undefined) {
return queryResource.latest?.data
const stateData = state.data

if (!observerResult.isFetching && stateData !== undefined) {
return stateData
}

if (!observerResult.isFetching && observerResult.data !== undefined) {
return observerResult.data
}

return queryResource()?.data
}
return Reflect.get(target, prop)
Expand Down