Skip to main content
Disabling queries allows you to control precisely when queries should run. This is essential for optimizing performance, handling user interactions, and managing dependent data flows.

Using the enabled Option

The enabled option controls whether a query should automatically run:
import { useQuery } from '@tanstack/react-query'

function UserProfile({ userId }) {
  const { data, isLoading, isError } = useQuery({
    queryKey: ['user', userId],
    queryFn: () => fetchUser(userId),
    enabled: !!userId, // Only run when userId is truthy
  })

  if (!userId) {
    return <div>Please select a user</div>
  }

  if (isLoading) return <div>Loading...</div>
  if (isError) return <div>Error loading user</div>

  return <div>{data.name}</div>
}
When enabled is false, the query will stay in an idle status and won’t execute until enabled becomes true.

Lazy Queries

Implement lazy loading by starting with enabled: false and manually triggering the query:
function SearchUsers() {
  const [searchTerm, setSearchTerm] = useState('')
  const [shouldSearch, setShouldSearch] = useState(false)

  const { data, refetch, isFetching } = useQuery({
    queryKey: ['users', searchTerm],
    queryFn: () => searchUsers(searchTerm),
    enabled: false, // Don't run automatically
  })

  const handleSearch = () => {
    setShouldSearch(true)
    refetch()
  }

  return (
    <div>
      <input
        value={searchTerm}
        onChange={(e) => setSearchTerm(e.target.value)}
        placeholder="Search users..."
      />
      <button onClick={handleSearch} disabled={!searchTerm}>
        Search
      </button>
      {isFetching && <div>Searching...</div>}
      {data && <UserList users={data} />}
    </div>
  )
}
1

Set enabled to false

Prevent the query from running automatically on mount.
2

Trigger with refetch

Call refetch() manually when you want to execute the query.
3

Handle loading states

Use isFetching to show loading indicators during manual fetches.

Conditional Query Execution

Enable queries based on complex conditions:
function Dashboard({ user }) {
  const hasPermission = user?.role === 'admin' || user?.role === 'manager'
  const isActive = user?.status === 'active'

  const { data: analyticsData } = useQuery({
    queryKey: ['analytics'],
    queryFn: fetchAnalytics,
    enabled: hasPermission && isActive,
  })

  if (!hasPermission || !isActive) {
    return <div>Access denied</div>
  }

  return <AnalyticsDashboard data={analyticsData} />
}
Combine multiple conditions in the enabled option to ensure all prerequisites are met before executing a query.

Function-Based enabled

Use a function for dynamic enable logic:
const { data } = useQuery({
  queryKey: ['user', userId],
  queryFn: () => fetchUser(userId),
  enabled: (query) => {
    // Access the query instance
    const hasError = query.state.error !== null
    const isStale = query.isStale()
    
    // Only enable if no error and user ID exists
    return !hasError && !!userId
  },
})

User-Triggered Queries

Fetch data only when the user explicitly requests it:
function EmailPreview({ emailId }) {
  const [showPreview, setShowPreview] = useState(false)

  const { data, isFetching } = useQuery({
    queryKey: ['email', emailId],
    queryFn: () => fetchEmail(emailId),
    enabled: showPreview && !!emailId,
  })

  return (
    <div>
      <button onClick={() => setShowPreview(true)}>
        Preview Email
      </button>
      {showPreview && (
        <div>
          {isFetching ? (
            <div>Loading preview...</div>
          ) : (
            <EmailContent data={data} />
          )}
        </div>
      )}
    </div>
  )
}
This pattern is useful for expensive queries or data that’s not needed immediately, reducing unnecessary API calls and improving initial load performance.

Tab-Based Query Activation

Load data only for the active tab:
function UserTabs({ userId }) {
  const [activeTab, setActiveTab] = useState('profile')

  const { data: profile } = useQuery({
    queryKey: ['profile', userId],
    queryFn: () => fetchUserProfile(userId),
    enabled: activeTab === 'profile',
  })

  const { data: activity } = useQuery({
    queryKey: ['activity', userId],
    queryFn: () => fetchUserActivity(userId),
    enabled: activeTab === 'activity',
  })

  const { data: settings } = useQuery({
    queryKey: ['settings', userId],
    queryFn: () => fetchUserSettings(userId),
    enabled: activeTab === 'settings',
  })

  return (
    <div>
      <div>
        <button onClick={() => setActiveTab('profile')}>Profile</button>
        <button onClick={() => setActiveTab('activity')}>Activity</button>
        <button onClick={() => setActiveTab('settings')}>Settings</button>
      </div>
      <div>
        {activeTab === 'profile' && <ProfileTab data={profile} />}
        {activeTab === 'activity' && <ActivityTab data={activity} />}
        {activeTab === 'settings' && <SettingsTab data={settings} />}
      </div>
    </div>
  )
}
If you want to cache data across tab switches, set enabled: true and use staleTime instead. Disabled queries won’t fetch data even if it’s stale.

Permanently Disabled Queries

Some queries should never run automatically:
function ExportData() {
  const { refetch, isFetching } = useQuery({
    queryKey: ['export'],
    queryFn: generateExport,
    enabled: false, // Never run automatically
    gcTime: 0, // Don't cache the result
  })

  const handleExport = async () => {
    const { data } = await refetch()
    downloadFile(data)
  }

  return (
    <button onClick={handleExport} disabled={isFetching}>
      {isFetching ? 'Generating...' : 'Export Data'}
    </button>
  )
}

Disabling During Mutations

Disable queries while mutations are in progress:
function EditablePost({ postId }) {
  const [isEditing, setIsEditing] = useState(false)

  const { data: post } = useQuery({
    queryKey: ['post', postId],
    queryFn: () => fetchPost(postId),
    enabled: !isEditing, // Don't refetch while editing
  })

  const updatePost = useMutation({
    mutationFn: (updates) => updatePostAPI(postId, updates),
    onSuccess: () => {
      setIsEditing(false)
      queryClient.invalidateQueries({ queryKey: ['post', postId] })
    },
  })

  return (
    <div>
      {isEditing ? (
        <PostEditor
          initialData={post}
          onSave={(data) => updatePost.mutate(data)}
          onCancel={() => setIsEditing(false)}
        />
      ) : (
        <PostDisplay
          data={post}
          onEdit={() => setIsEditing(true)}
        />
      )}
    </div>
  )
}
Disabling queries during editing prevents race conditions where background refetches could overwrite user changes.

Query Status with Disabled

Understand how query status works with enabled: false:
const { status, fetchStatus, data } = useQuery({
  queryKey: ['user', userId],
  queryFn: () => fetchUser(userId),
  enabled: !!userId,
})

// When enabled is false:
// - status: 'pending' (no data yet) or 'success' (has cached data)
// - fetchStatus: 'idle' (not fetching)
// - data: undefined or previous cached data

if (fetchStatus === 'idle' && status === 'pending') {
  return <div>Waiting to fetch...</div>
}
A disabled query can have status: 'success' if it has cached data from a previous fetch, but fetchStatus will be 'idle' indicating it’s not currently fetching.

Re-enabling Queries

Queries automatically run when enabled changes from false to true:
function ConditionalData({ shouldLoad }) {
  const { data, isFetching } = useQuery({
    queryKey: ['data'],
    queryFn: fetchData,
    enabled: shouldLoad, // Automatically fetches when this becomes true
  })

  return (
    <div>
      {isFetching && <div>Loading...</div>}
      {data && <DataDisplay data={data} />}
    </div>
  )
}

Refetch with enabled: false

You can manually refetch even when enabled is false:
const { data, refetch } = useQuery({
  queryKey: ['data'],
  queryFn: fetchData,
  enabled: false,
})

// This works even though enabled is false
const handleManualRefetch = () => {
  refetch()
}
Use refetch() for one-time manual fetches and enabled for controlling automatic fetching behavior (on mount, window focus, network reconnect, etc.).

Combining with Other Options

Disabled queries work alongside other query options:
const { data } = useQuery({
  queryKey: ['user', userId],
  queryFn: () => fetchUser(userId),
  enabled: !!userId,
  staleTime: 5000, // Still applies when query is enabled
  retry: 3, // Still applies to failed fetches
  refetchOnWindowFocus: false, // Prevents refetch on focus
})

Debugging Disabled Queries

Use the devtools to inspect disabled queries:
import { ReactQueryDevtools } from '@tanstack/react-query-devtools'

function App() {
  return (
    <>
      <YourApp />
      <ReactQueryDevtools initialIsOpen={false} />
    </>
  )
}
In the devtools, disabled queries show with a “disabled” badge, helping you identify why a query isn’t fetching.

Build docs developers (and LLMs) love