Skip to content

Commit

Permalink
fix(solid-query): Fix race condition issues with createQuery (#7748)
Browse files Browse the repository at this point in the history
* fix(solid-query): Fix race condition issues with `createQuery`
  • Loading branch information
ardeora committed Jul 17, 2024
1 parent c101251 commit ffb11b3
Show file tree
Hide file tree
Showing 2 changed files with 123 additions and 1 deletion.
118 changes: 118 additions & 0 deletions packages/solid-query/src/__tests__/createQuery.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3528,6 +3528,124 @@ describe('createQuery', () => {
])
})

// See https://github.com/TanStack/query/issues/7711
it('race condition: should cleanup observers after component that created the query is unmounted #1', async () => {
const key = queryKey()

function Component() {
let val = 1
const dataQuery = createQuery(() => ({
queryKey: [key],
queryFn: () => {
return val++
},
}))

return (
<div>
<p>component</p>
<p>data: {String(dataQuery.data)}</p>
</div>
)
}

const Outer = () => {
const [showComp, setShowComp] = createSignal(true)
return (
<div>
<button
onClick={() => {
queryClient.invalidateQueries()
setShowComp(!showComp())
}}
>
toggle
</button>
{showComp() ? <Component /> : <div>not showing</div>}
</div>
)
}

const rendered = render(() => (
<QueryClientProvider client={queryClient}>
<Outer />
</QueryClientProvider>
))

await waitFor(() => rendered.getByText('component'))
fireEvent.click(rendered.getByText('toggle'))
await waitFor(() => rendered.getByText('not showing'))
fireEvent.click(rendered.getByText('toggle'))
await waitFor(() => rendered.getByText('component'))
fireEvent.click(rendered.getByText('toggle'))
await waitFor(() => rendered.getByText('not showing'))

const entry = queryClient.getQueryCache().find({
queryKey: [key],
})!

expect(entry.getObserversCount()).toBe(0)
})

// See https://github.com/TanStack/query/issues/7711
it('race condition: should cleanup observers after component that created the query is unmounted #2', async () => {
const key = queryKey()

function Component() {
let val = 1
const dataQuery = createQuery(() => ({
queryKey: [key],
queryFn: () => {
return val++
},
}))

return (
<div>
<p>component</p>
<p>data: {String(dataQuery.data)}</p>
</div>
)
}

const Outer = () => {
const [showComp, setShowComp] = createSignal(true)
return (
<div>
<button
onClick={() => {
queueMicrotask(() => setShowComp(!showComp()))
queryClient.invalidateQueries()
}}
>
toggle
</button>
{showComp() ? <Component /> : <div>not showing</div>}
</div>
)
}

const rendered = render(() => (
<QueryClientProvider client={queryClient}>
<Outer />
</QueryClientProvider>
))

await waitFor(() => rendered.getByText('component'))
fireEvent.click(rendered.getByText('toggle'))
await waitFor(() => rendered.getByText('not showing'))
fireEvent.click(rendered.getByText('toggle'))
await waitFor(() => rendered.getByText('component'))
fireEvent.click(rendered.getByText('toggle'))
await waitFor(() => rendered.getByText('not showing'))

const entry = queryClient.getQueryCache().find({
queryKey: [key],
})!

expect(entry.getObserversCount()).toBe(0)
})

it('should mark query as fetching, when using initialData', async () => {
const key = queryKey()
const results: Array<DefinedCreateQueryResult<string>> = []
Expand Down
6 changes: 5 additions & 1 deletion packages/solid-query/src/createBaseQuery.ts
Original file line number Diff line number Diff line change
Expand Up @@ -179,7 +179,11 @@ export function createBaseQuery<
const obs = observer()
return obs.subscribe((result) => {
observerResult = result
queueMicrotask(() => refetch())
queueMicrotask(() => {
if (unsubscribe) {
refetch()
}
})
})
}

Expand Down

0 comments on commit ffb11b3

Please sign in to comment.