框架
版本

React Native

React Query 旨在与 React Native 开箱即用。

开发者工具支持

有几个选项可用于 React Native DevTools 集成

  1. macOS 原生应用:一个用于调试任何基于 JS 的应用程序中 React Query 的第三方应用:https://github.com/LovesWorking/rn-better-dev-tools

  2. Flipper 插件:一个适用于 Flipper 用户的第三方插件:https://github.com/bgaleotti/react-query-native-devtools

  3. Reactotron 插件:一个适用于 Reactotron 用户的第三方插件:https://github.com/hsndmr/reactotron-react-query

在线状态管理

React Query 已支持在网络浏览器中重新连接时自动重新获取。要在 React Native 中添加此行为,您必须使用 React Query onlineManager,如以下示例所示

tsx
import NetInfo from '@react-native-community/netinfo'
import { onlineManager } from '@tanstack/react-query'

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

onlineManager.setEventListener((setOnline) => {
  return NetInfo.addEventListener((state) => {
    setOnline(!!state.isConnected)
  })
})

tsx
import { onlineManager } from '@tanstack/react-query'
import * as Network from 'expo-network'

onlineManager.setEventListener((setOnline) => {
  const eventSubscription = Network.addNetworkStateListener((state) => {
    setOnline(!!state.isConnected)
  })
  return eventSubscription.remove
})
import { onlineManager } from '@tanstack/react-query'
import * as Network from 'expo-network'

onlineManager.setEventListener((setOnline) => {
  const eventSubscription = Network.addNetworkStateListener((state) => {
    setOnline(!!state.isConnected)
  })
  return eventSubscription.remove
})

应用聚焦时重新获取数据

React Native 不使用 window 上的事件监听器,而是通过 AppState 模块 提供焦点信息。当应用状态变为“active”时,您可以使用 AppState “change”事件来触发更新

tsx
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()
}, [])
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()
}, [])

屏幕聚焦时刷新数据

在某些情况下,您可能希望在 React Native 屏幕再次聚焦时重新获取查询。当屏幕再次聚焦时,此自定义 hook 将重新获取所有活动且陈旧的查询

tsx
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]),
  )
}
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]),
  )
}

在上述代码中,第一次聚焦(当屏幕最初挂载时)被跳过,因为 useFocusEffect 除了屏幕聚焦外,在挂载时也会调用我们的回调。

在未聚焦的屏幕上禁用查询

如果您不希望某些查询在屏幕失去焦点时保持“实时”,您可以使用 useQuery 上的 subscribed 属性。此属性允许您控制查询是否订阅更新。结合 React Navigation 的 useIsFocused,它允许您在屏幕未聚焦时无缝地取消订阅查询

用法示例

tsx
import React from 'react'
import { useIsFocused } from '@react-navigation/native'
import { useQuery } from '@tanstack/react-query'
import { Text } from 'react-native'

function MyComponent() {
  const isFocused = useIsFocused()

  const { dataUpdatedAt } = useQuery({
    queryKey: ['key'],
    queryFn: () => fetch(...),
    subscribed: isFocused,
  })

  return <Text>DataUpdatedAt: {dataUpdatedAt}</Text>
}
import React from 'react'
import { useIsFocused } from '@react-navigation/native'
import { useQuery } from '@tanstack/react-query'
import { Text } from 'react-native'

function MyComponent() {
  const isFocused = useIsFocused()

  const { dataUpdatedAt } = useQuery({
    queryKey: ['key'],
    queryFn: () => fetch(...),
    subscribed: isFocused,
  })

  return <Text>DataUpdatedAt: {dataUpdatedAt}</Text>
}

当 subscribed 为 false 时,查询将取消订阅更新,并且不会触发该屏幕的重新渲染或获取新数据。一旦它再次变为 true(例如,当屏幕重新获得焦点时),查询将重新订阅并保持最新。