React Native

Purpose and Scope

React Query is documented as working out of the box with React Native, so a normal React Native application can use the React adapter rather than a separate native-only adapter. The platform-specific work begins where browser assumptions differ: browsers expose window focus and online events, while React Native applications need mobile connectivity and lifecycle sources. This page explains those integration points for teams that already understand queries, cache freshness, and providers, but need to make refetching behavior match mobile app reality. It focuses on connectivity, app focus, screen focus, and React Native devtools options rather than installation basics.

Sources: docs/framework/react/react-native.md

React Native usage is best understood as standard TanStack Query plus explicit signals. Queries still represent asynchronous server state, stale data can still be refetched in the background, and active observers still drive live updates. What changes is how the library learns that the device is online, that the app has returned to the foreground, or that a particular navigation screen has become relevant again. The documented hooks into onlineManager, focusManager, useQueryClient, useFocusEffect, useIsFocused, and useQuery provide those bridges without changing the cache model.

Sources: docs/framework/react/react-native.md

Relevant Source Files

  • docs/framework/react/react-native.md - First-party React Native guide covering out-of-the-box support, React Native devtools options, network status listeners, app focus handling, screen focus refetching, and unsubscribing queries for screens that are not focused.

Core Primitives for React Native

The two global primitives in this guide are the online manager and the focus manager. The online manager receives connectivity changes and enables reconnect behavior that browser users normally get from web events. The focus manager receives application focus changes and lets TanStack Query know whether foreground-oriented refetch behavior should run. In React Native, both managers are fed by platform libraries: network libraries report connection status, and React Native AppState reports whether the app is active. This keeps application code explicit while allowing the query cache and observers to keep using the same core semantics.

Sources: docs/framework/react/react-native.md

At the screen level, the key primitives are the query client and the navigation focus hooks. The guide shows useQueryClient paired with React Navigation useFocusEffect to refetch stale active queries when a screen becomes focused again. It also introduces useIsFocused with the subscribed option on useQuery for screens that should stop receiving updates while out of focus. These patterns solve different problems: one refreshes data after navigation, while the other reduces live subscriptions for UI that is currently not visible.

Sources: docs/framework/react/react-native.md

Online Status Management

React Query already supports automatic refetching on reconnect in the web browser, but React Native does not provide the same browser online event source. The documented mobile approach is to set an event listener on onlineManager and call the provided setter whenever connectivity changes. With @react-native-community/netinfo, the integration is direct: subscribe to NetInfo changes, read state.isConnected, coerce it to a boolean, and return NetInfo’s unsubscribe function so the listener can be cleaned up when TanStack Query replaces or removes the event listener.

Sources: docs/framework/react/react-native.md

import NetInfo from '@react-native-community/netinfo'
import { onlineManager } from '@tanstack/react-query'
 
onlineManager.setEventListener((setOnline) => {
  return NetInfo.addEventListener((state) => {
    setOnline(!!state.isConnected)
  })
})

Expo applications can use expo-network instead. The documented Expo version is slightly more defensive because it combines an event listener with an initial asynchronous network-state lookup. The code tracks whether the event listener has already produced a value, then calls Network.getNetworkStateAsync() to initialize the online state if no event has arrived yet. It also catches rejections because the asynchronous call can fail on some platforms or SDK versions. That defensive catch is important in mobile code because platform APIs can vary across device, operating system, and Expo runtime versions.

Sources: docs/framework/react/react-native.md

import { onlineManager } from '@tanstack/react-query'
import * as Network from 'expo-network'
 
onlineManager.setEventListener((setOnline) => {
  let initialised = false
 
  const eventSubscription = Network.addNetworkStateListener((state) => {
    initialised = true
    setOnline(!!state.isConnected)
  })
 
  Network.getNetworkStateAsync()
    .then((state) => {
      if (!initialised) {
        setOnline(!!state.isConnected)
      }
    })
    .catch(() => {
      // getNetworkStateAsync can reject on some platforms/SDK versions
    })
 
  return eventSubscription.remove
})

Refetching on App and Screen Focus

Browser examples commonly describe refetching on window focus, but React Native uses the AppState module for app lifecycle information. The guide maps the AppState change event to focusManager.setFocused, treating the app as focused when the status is active. It also guards against web by checking the platform before setting focus. That distinction matters for shared React Native Web code: a web build may already have browser focus handling, while native builds need AppState to provide equivalent foreground and background information.

Sources: docs/framework/react/react-native.md

import { useEffect } from 'react'
import { AppState, Platform } from 'react-native'
import type { AppStateStatus } from 'react-native'
import { focusManager } from '@tanstack/react-query'
 
function onAppStateChange(status: AppStateStatus) {
  if (Platform.OS !== 'web') {
    focusManager.setFocused(status === 'active')
  }
}
 
useEffect(() => {
  const subscription = AppState.addEventListener('change', onAppStateChange)
 
  return () => subscription.remove()
}, [])

Navigation focus is narrower than app focus. A React Native app can be foregrounded while a specific screen remains hidden behind another route, tab, or stack entry. The guide’s useRefreshOnFocus hook uses React Navigation’s useFocusEffect and a firstTimeRef guard so it does not refetch on the initial mount. After the first focus, it calls queryClient.refetchQueries with a query key, stale: true, and type: 'active', so the refetch is limited to active stale queries matching the intended cache identity.

Sources: docs/framework/react/react-native.md

import React from 'react'
import { useFocusEffect } from '@react-navigation/native'
import { useQueryClient } from '@tanstack/react-query'
 
export function useRefreshOnFocus() {
  const queryClient = useQueryClient()
  const firstTimeRef = React.useRef(true)
 
  useFocusEffect(
    React.useCallback(() => {
      if (firstTimeRef.current) {
        firstTimeRef.current = false
        return
      }
 
      // refetch all stale active queries
      queryClient.refetchQueries({
        queryKey: ['posts'],
        stale: true,
        type: 'active',
      })
    }, [queryClient]),
  )
}

Disabling Queries on Out-of-Focus Screens

Refetching on focus is useful when a screen returns, but some screens should also stop listening while they are hidden. The guide recommends the subscribed prop on useQuery for this case. Combined with React Navigation’s useIsFocused, a query can remain in the cache without keeping an out-of-focus screen subscribed to updates. This is different from deleting data or permanently disabling a query: it is a visibility-aware subscription control that helps prevent hidden screens from reacting to cache updates that are not currently user-visible.

Sources: docs/framework/react/react-native.md

This distinction is especially useful in mobile navigation trees where many screens may remain mounted for performance or navigation state preservation. A tab can stay mounted while another tab is visible, and a stack screen can remain in memory while the user moves deeper into the app. Keeping every mounted screen live can cause unnecessary renders or unexpected state transitions. Using focus state as the subscription condition lets TanStack Query continue managing cache data centrally while individual screens decide whether they should observe changes at that moment.

Sources: docs/framework/react/react-native.md

DevTools and Operational Choices

The React Native guide lists three devtools paths rather than a built-in browser overlay. A native macOS app can debug React Query in JavaScript-based applications, a Flipper plugin serves teams already using Flipper, and a Reactotron plugin serves Reactotron workflows. The important decision is operational rather than conceptual: choose the tool that fits the team’s existing mobile debugging environment. TanStack Query still exposes the same cache, queries, and mutation state, but the mobile inspection surface is supplied through third-party React Native tooling rather than the standard browser-oriented devtools panel.

Sources: docs/framework/react/react-native.md

Offline-related behavior in this page is centered on online detection and reconnect refetching, not durable storage. If an application also needs to survive process death or long offline periods with cached data restored from device storage, pair this page with the persistence and storage-persister documentation. The network listener decides whether TanStack Query should consider the app online; persistence decides whether cached query data can be saved and restored across sessions. Those concerns complement each other but should be configured and tested separately in mobile applications.

Sources: docs/framework/react/react-native.md

Reference Checklist and Next Steps

For a production React Native setup, install and configure the normal React Query provider first, then add platform signals near the root of the application. Register exactly one online listener appropriate for the runtime, such as NetInfo for bare React Native or Expo Network for Expo. Register AppState focus handling once, and keep the cleanup function returned by the event subscription. Add screen-level refetching only where navigation focus should refresh stale active data, and use subscription control for screens that should not remain live while hidden.

Sources: docs/framework/react/react-native.md

When adapting the examples, keep the cache identity explicit. The screen-focus example refetches queries with the ['posts'] key, so real applications should replace that key with the same structured query keys used by their feature modules. Keep the stale: true filter if the goal is a freshness check rather than a forced network request for every active query. After implementing the platform listeners, test foregrounding, backgrounding, losing connectivity, reconnecting, switching tabs, and navigating back to a previously mounted screen.

Sources: docs/framework/react/react-native.md

Related pages to read next: Quick Start for provider setup, Important Defaults for freshness and refetch behavior, Network Mode for online and offline execution semantics, Background Refetching for user-visible fetching indicators, Persist Query Client for restored cache workflows, Storage Persisters for device storage choices, and Devtools for the wider TanStack Query inspection tooling.