diff --git a/.changeset/preact-unsubscribed-optimistic-state.md b/.changeset/preact-unsubscribed-optimistic-state.md
new file mode 100644
index 0000000000..b445ff975a
--- /dev/null
+++ b/.changeset/preact-unsubscribed-optimistic-state.md
@@ -0,0 +1,5 @@
+---
+'@tanstack/preact-query': patch
+---
+
+fix(preact-query): do not go into optimistic fetching state when not subscribed
diff --git a/packages/preact-query/src/__tests__/unsubscribed-optimistic.test.tsx b/packages/preact-query/src/__tests__/unsubscribed-optimistic.test.tsx
new file mode 100644
index 0000000000..588433bd28
--- /dev/null
+++ b/packages/preact-query/src/__tests__/unsubscribed-optimistic.test.tsx
@@ -0,0 +1,92 @@
+import { queryKey } from '@tanstack/query-test-utils'
+import { fireEvent } from '@testing-library/preact'
+import { useState } from 'preact/hooks'
+import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest'
+
+import { QueryCache, QueryClient, useQuery } from '..'
+import { renderWithClient } from './utils'
+
+describe('useQuery unsubscribed optimistic state', () => {
+ let queryClient: QueryClient
+
+ beforeEach(() => {
+ queryClient = new QueryClient({ queryCache: new QueryCache() })
+ vi.useFakeTimers()
+ })
+
+ afterEach(() => {
+ queryClient.clear()
+ vi.useRealTimers()
+ })
+
+ it('should not show fetching on re-render when unsubscribed', async () => {
+ const key = queryKey()
+ const queryFn = vi.fn(() => Promise.resolve('data'))
+
+ function Page() {
+ const [subscribed, setSubscribed] = useState(true)
+ const [other, setOther] = useState(false)
+ const query = useQuery({
+ queryKey: key,
+ queryFn,
+ subscribed,
+ })
+
+ return (
+
+ isFetching: {String(query.isFetching)}
+ fetchStatus: {query.fetchStatus}
+
+
+
+ )
+ }
+
+ const rendered = renderWithClient(queryClient, )
+ await vi.advanceTimersByTimeAsync(0)
+ rendered.getByText('isFetching: false')
+ rendered.getByText('fetchStatus: idle')
+
+ fireEvent.click(rendered.getByRole('button', { name: 'unsubscribe' }))
+ await vi.advanceTimersByTimeAsync(0)
+
+ expect(queryFn).toHaveBeenCalledTimes(1)
+ expect(
+ queryClient.getQueryCache().find({ queryKey: key })!.observers.length,
+ ).toBe(0)
+
+ // re-render while unsubscribed
+ fireEvent.click(rendered.getByRole('button', { name: 'rerender' }))
+ await vi.advanceTimersByTimeAsync(0)
+
+ rendered.getByText('isFetching: false')
+ rendered.getByText('fetchStatus: idle')
+ })
+
+ it('should not show fetching when unsubscribed from the start', async () => {
+ const key = queryKey()
+ const queryFn = vi.fn(() => Promise.resolve('data'))
+
+ function Page() {
+ const query = useQuery({
+ queryKey: key,
+ queryFn,
+ subscribed: false,
+ })
+
+ return (
+
+ isFetching: {String(query.isFetching)}
+ fetchStatus: {query.fetchStatus}
+
+ )
+ }
+
+ const rendered = renderWithClient(queryClient, )
+ await vi.advanceTimersByTimeAsync(0)
+
+ expect(queryFn).toHaveBeenCalledTimes(0)
+ rendered.getByText('isFetching: false')
+ rendered.getByText('fetchStatus: idle')
+ })
+})
diff --git a/packages/preact-query/src/useBaseQuery.ts b/packages/preact-query/src/useBaseQuery.ts
index e5e37cbc52..c05aa8aa29 100644
--- a/packages/preact-query/src/useBaseQuery.ts
+++ b/packages/preact-query/src/useBaseQuery.ts
@@ -71,9 +71,12 @@ export function useBaseQuery<
}
// Make sure results are optimistically set in fetching state before subscribing or updating options
+ const subscribed = options.subscribed !== false
defaultedOptions._optimisticResults = isRestoring
? 'isRestoring'
- : 'optimistic'
+ : subscribed
+ ? 'optimistic'
+ : undefined
ensureSuspenseTimers(defaultedOptions)
ensurePreventErrorBoundaryRetry(defaultedOptions, errorResetBoundary, query)
@@ -91,7 +94,7 @@ export function useBaseQuery<
// note: this must be called before useSyncExternalStore
const result = observer.getOptimisticResult(defaultedOptions)
- const shouldSubscribe = !isRestoring && options.subscribed !== false
+ const shouldSubscribe = !isRestoring && subscribed
useSyncExternalStore(
useCallback(
(onStoreChange) => {