Skip to content
Draft
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
5 changes: 5 additions & 0 deletions .changeset/solid-query-client-resolver.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
'@tanstack/solid-query': patch
---

Resolve the query client context outside reactive memo callbacks.
26 changes: 24 additions & 2 deletions packages/solid-query/src/QueryClientProvider.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,25 +5,47 @@ import {
useContext,
} from 'solid-js'
import type { QueryClient } from './QueryClient'
import type { JSX } from 'solid-js'
import type { Accessor, JSX } from 'solid-js'

export const QueryClientContext = createContext<
(() => QueryClient) | undefined
>(undefined)

const queryClientContextError =
'No QueryClient set, use QueryClientProvider to set one'

export const useQueryClient = (queryClient?: QueryClient) => {
if (queryClient) {
return queryClient
}
const client = useContext(QueryClientContext)

if (!client) {
throw new Error('No QueryClient set, use QueryClientProvider to set one')
throw new Error(queryClientContextError)
}

return client()
}

export const useQueryClientResolver = (
queryClient?: Accessor<QueryClient | undefined>,
): Accessor<QueryClient> => {
const contextClient = useContext(QueryClientContext)

return () => {
const resolvedClient = queryClient?.()
if (resolvedClient) {
return resolvedClient
}

if (!contextClient) {
throw new Error(queryClientContextError)
}

return contextClient()
}
}

export type QueryClientProviderProps = {
client: QueryClient
children?: JSX.Element
Expand Down
25 changes: 25 additions & 0 deletions packages/solid-query/src/__tests__/QueryClientProvider.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,9 @@ import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest'
import { render } from '@solidjs/testing-library'
import { QueryCache } from '@tanstack/query-core'
import { queryKey, sleep } from '@tanstack/query-test-utils'
import { createMemo, createRoot } from 'solid-js'
import { QueryClient, QueryClientProvider, useQuery, useQueryClient } from '..'
import { useQueryClientResolver } from '../QueryClientProvider'

describe('QueryClientProvider', () => {
beforeEach(() => {
Expand Down Expand Up @@ -174,4 +176,27 @@ describe('QueryClientProvider', () => {

consoleMock.mockRestore()
})

it('creates a query client resolver that is safe to call in reactive callbacks', () => {
const queryClient = new QueryClient()
let resolveClient!: () => QueryClient

function Page() {
resolveClient = useQueryClientResolver()
return null
}

render(() => (
<QueryClientProvider client={queryClient}>
<Page />
</QueryClientProvider>
))

createRoot((dispose) => {
const client = createMemo(() => resolveClient())

expect(client()).toBe(queryClient)
dispose()
})
})
})
5 changes: 3 additions & 2 deletions packages/solid-query/src/useBaseQuery.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ import {
onCleanup,
} from 'solid-js'
import { createStore, reconcile, unwrap } from 'solid-js/store'
import { useQueryClient } from './QueryClientProvider'
import { useQueryClientResolver } from './QueryClientProvider'
import { useIsRestoring } from './isRestoring'
import type { UseBaseQueryOptions } from './types'
import type { Accessor, Signal } from 'solid-js'
Expand Down Expand Up @@ -115,7 +115,8 @@ export function useBaseQuery<
) {
type ResourceData = QueryObserverResult<TData, TError>

const client = createMemo(() => useQueryClient(queryClient?.()))
const resolveClient = useQueryClientResolver(queryClient)
const client = createMemo(() => resolveClient())
const isRestoring = useIsRestoring()
// There are times when we run a query on the server but the resource is never read
// This could lead to times when the queryObserver is unsubscribed before the resource has loaded
Expand Down
5 changes: 3 additions & 2 deletions packages/solid-query/src/useIsFetching.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { createMemo, createSignal, onCleanup } from 'solid-js'
import { useQueryClient } from './QueryClientProvider'
import { useQueryClientResolver } from './QueryClientProvider'
import type { QueryFilters } from '@tanstack/query-core'
import type { QueryClient } from './QueryClient'
import type { Accessor } from 'solid-js'
Expand All @@ -8,7 +8,8 @@ export function useIsFetching(
filters?: Accessor<QueryFilters>,
queryClient?: Accessor<QueryClient>,
): Accessor<number> {
const client = createMemo(() => useQueryClient(queryClient?.()))
const resolveClient = useQueryClientResolver(queryClient)
const client = createMemo(() => resolveClient())
const queryCache = createMemo(() => client().getQueryCache())

const [fetches, setFetches] = createSignal(client().isFetching(filters?.()))
Expand Down
5 changes: 3 additions & 2 deletions packages/solid-query/src/useIsMutating.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { createMemo, createSignal, onCleanup } from 'solid-js'
import { useQueryClient } from './QueryClientProvider'
import { useQueryClientResolver } from './QueryClientProvider'
import type { MutationFilters } from '@tanstack/query-core'
import type { QueryClient } from './QueryClient'
import type { Accessor } from 'solid-js'
Expand All @@ -8,7 +8,8 @@ export function useIsMutating(
filters?: Accessor<MutationFilters>,
queryClient?: Accessor<QueryClient>,
): Accessor<number> {
const client = createMemo(() => useQueryClient(queryClient?.()))
const resolveClient = useQueryClientResolver(queryClient)
const client = createMemo(() => resolveClient())
const mutationCache = createMemo(() => client().getMutationCache())

const [mutations, setMutations] = createSignal(
Expand Down
5 changes: 3 additions & 2 deletions packages/solid-query/src/useMutation.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { MutationObserver, noop, shouldThrowError } from '@tanstack/query-core'
import { createComputed, createMemo, on, onCleanup } from 'solid-js'
import { createStore } from 'solid-js/store'
import { useQueryClient } from './QueryClientProvider'
import { useQueryClientResolver } from './QueryClientProvider'
import type { DefaultError } from '@tanstack/query-core'
import type { QueryClient } from './QueryClient'
import type {
Expand All @@ -21,7 +21,8 @@ export function useMutation<
options: UseMutationOptions<TData, TError, TVariables, TOnMutateResult>,
queryClient?: Accessor<QueryClient>,
): UseMutationResult<TData, TError, TVariables, TOnMutateResult> {
const client = createMemo(() => useQueryClient(queryClient?.()))
const resolveClient = useQueryClientResolver(queryClient)
const client = createMemo(() => resolveClient())

const observer = new MutationObserver<
TData,
Expand Down
5 changes: 3 additions & 2 deletions packages/solid-query/src/useMutationState.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { createEffect, createMemo, createSignal, onCleanup } from 'solid-js'
import { replaceEqualDeep } from '@tanstack/query-core'
import { useQueryClient } from './QueryClientProvider'
import { useQueryClientResolver } from './QueryClientProvider'
import type {
Mutation,
MutationCache,
Expand Down Expand Up @@ -31,7 +31,8 @@ export function useMutationState<TResult = MutationState>(
options: Accessor<MutationStateOptions<TResult>> = () => ({}),
queryClient?: Accessor<QueryClient>,
): Accessor<Array<TResult>> {
const client = createMemo(() => useQueryClient(queryClient?.()))
const resolveClient = useQueryClientResolver(queryClient)
const client = createMemo(() => resolveClient())
const mutationCache = createMemo(() => client().getMutationCache())

const [result, setResult] = createSignal(
Expand Down
5 changes: 3 additions & 2 deletions packages/solid-query/src/useQueries.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ import {
onCleanup,
onMount,
} from 'solid-js'
import { useQueryClient } from './QueryClientProvider'
import { useQueryClientResolver } from './QueryClientProvider'
import { useIsRestoring } from './isRestoring'
import type { SolidQueryOptions, UseQueryResult } from './types'
import type { Accessor } from 'solid-js'
Expand Down Expand Up @@ -196,7 +196,8 @@ export function useQueries<
}>,
queryClient?: Accessor<QueryClient>,
): TCombinedResult {
const client = createMemo(() => useQueryClient(queryClient?.()))
const resolveClient = useQueryClientResolver(queryClient)
const client = createMemo(() => resolveClient())
const isRestoring = useIsRestoring()

const defaultedQueries = createMemo(() =>
Expand Down
Loading