🔥 React Native

597자
6분

React Query는 React Native와 함께 사용할 수 있도록 설계되었습니다. 단, 개발 도구는 현재 React DOM에서만 지원됩니다.

React Native 환경에서 개발 도구를 사용하고 싶다면 다음과 같은 제3자 플러그인을 활용할 수 있습니다:

  1. Expo 플러그인: https://github.com/expo/dev-plugins/tree/main/packages/react-query
  2. Flipper 플러그인: https://github.com/bgaleotti/react-query-native-devtools
  3. Reactotron 플러그인: https://github.com/hsndmr/reactotron-react-query

React Query 팀은 내장 개발 도구를 다양한 플랫폼에서 사용할 수 있도록 만들고 싶어 합니다. 이 작업에 도움을 주고 싶다면 연락 주시기 바랍니다!

온라인 상태 관리

React Query는 웹 브라우저에서 자동으로 재연결 시 다시 가져오기 기능을 지원합니다. React Native에서 이 기능을 사용하려면 React Query의 onlineManager를 다음과 같이 활용해야 합니다:

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

앱 포커스 시 다시 가져오기

React Native에서는 창 이벤트 리스너 대신 AppState 모듈을 통해 포커스 정보를 제공합니다. AppState의 "change" 이벤트를 사용하여 앱 상태가 "active"로 변경될 때 업데이트를 트리거할 수 있습니다:

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

화면 포커스 시 새로 고침

React Native 화면이 다시 포커스를 받을 때 쿼리를 다시 가져오고 싶을 수 있습니다. 다음 사용자 정의 훅은 화면이 다시 포커스를 받을 때 제공된 refetch 함수를 호출합니다:

import React from 'react'
import { useFocusEffect } from '@react-navigation/native'
 
export function useRefreshOnFocus<T>(refetch: () => Promise<T>) {
  const firstTimeRef = React.useRef(true)
 
  useFocusEffect(
    React.useCallback(() => {
      if (firstTimeRef.current) {
        firstTimeRef.current = false
        return
      }
 
      refetch()
    }, [refetch]),
  )
}
 
typescript

이 코드에서는 useFocusEffect가 마운트 시에도 콜백을 호출하기 때문에 처음에는 refetch를 건너뜁니다.

포커스를 잃은 화면에서 재렌더링 비활성화

성능 문제 등의 이유로 React Native 화면이 포커스를 잃었을 때 재렌더링을 중지하고 싶을 수 있습니다. 이를 위해 @react-navigation/native의 useFocusEffect와 쿼리의 notifyOnChangeProps 옵션을 함께 사용할 수 있습니다.

다음 사용자 정의 훅은 화면이 포커스를 잃었을 때 빈 배열을 반환하는 notifyOnChangeProps 옵션을 제공합니다. 이렇게 하면 해당 상황에서 재렌더링이 중지됩니다. 화면이 다시 포커스를 받으면 정상적인 동작으로 돌아갑니다:

import React from 'react'
import { NotifyOnChangeProps } from '@tanstack/query-core'
import { useFocusEffect } from '@react-navigation/native'
 
export function useFocusNotifyOnChangeProps(
  notifyOnChangeProps?: NotifyOnChangeProps,
) {
  const focusedRef = React.useRef(true)
 
  useFocusEffect(
    React.useCallback(() => {
      focusedRef.current = true
 
      return () => {
        focusedRef.current = false
      }
    }, []),
  )
 
  return () => {
    if (!focusedRef.current) {
      return []
    }
 
    if (typeof notifyOnChangeProps === 'function') {
      return notifyOnChangeProps()
    }
 
    return notifyOnChangeProps
  }
}
 
typescript

이 코드에서는 useFocusEffect를 사용하여 콜백이 조건으로 사용할 참조 값을 변경합니다.

인자는 반환된 콜백이 항상 동일한 참조를 유지하도록 참조로 감싸집니다.

사용 예제:

function MyComponent() {
  const notifyOnChangeProps = useFocusNotifyOnChangeProps()
 
  const { dataUpdatedAt } = useQuery({
    queryKey: ['myKey'],
    queryFn: async () => {
      const response = await fetch(
        '<https://api.github.com/repos/tannerlinsley/react-query>',
      )
      return response.json()
    },
    notifyOnChangeProps,
  })
 
  return <Text>DataUpdatedAt: {dataUpdatedAt}</Text>
}
 
typescript

포커스를 잃은 화면에서 쿼리 비활성화

enabled 옵션을 콜백으로 설정하면 상태와 네비게이션 시 재렌더링 없이 포커스를 잃은 화면에서 쿼리를 비활성화할 수 있습니다. 이는 notifyOnChangeProps와 유사하게 작동하지만, refetchType이 active인 쿼리를 무효화할 때 다시 가져오기를 트리거하지 않습니다.

import React from 'react'
import { useFocusEffect } from '@react-navigation/native'
 
export function useQueryFocusAware(notifyOnChangeProps?: NotifyOnChangeProps) {
  const focusedRef = React.useRef(true)
 
  useFocusEffect(
    React.useCallback(() => {
      focusedRef.current = true
 
      return () => {
        focusedRef.current = false
      }
    }, []),
  )
 
  return () => focusRef.current
 
  useQuery({
    queryKey: ['key'],
    queryFn: () => fetch(...),
    enabled: () => focusedRef.current,
  })
}
 
typescript

이렇게 React Native 환경에서 React Query를 효과적으로 사용할 수 있습니다. 온라인 상태 관리, 앱 포커스 시 다시 가져오기, 화면 포커스 시 새로 고침 등의 기능을 활용하여 앱의 성능과 사용자 경험을 향상시킬 수 있습니다.