🔥 React Native
React Query는 React Native와 함께 사용할 수 있도록 설계되었습니다. 단, 개발 도구는 현재 React DOM에서만 지원됩니다.
React Native 환경에서 개발 도구를 사용하고 싶다면 다음과 같은 제3자 플러그인을 활용할 수 있습니다:
- Expo 플러그인: https://github.com/expo/dev-plugins/tree/main/packages/react-query
- Flipper 플러그인: https://github.com/bgaleotti/react-query-native-devtools
- 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)
})
})
import NetInfo from '@react-native-community/netinfo'
import { onlineManager } from '@tanstack/react-query'
onlineManager.setEventListener((setOnline) => {
return NetInfo.addEventListener((state) => {
setOnline(!!state.isConnected)
})
})
앱 포커스 시 다시 가져오기
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()
}, [])
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 화면이 다시 포커스를 받을 때 쿼리를 다시 가져오고 싶을 수 있습니다. 다음 사용자 정의 훅은 화면이 다시 포커스를 받을 때 제공된 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]),
)
}
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]),
)
}
이 코드에서는 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
}
}
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
}
}
이 코드에서는 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>
}
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>
}
포커스를 잃은 화면에서 쿼리 비활성화
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,
})
}
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,
})
}
이렇게 React Native 환경에서 React Query를 효과적으로 사용할 수 있습니다. 온라인 상태 관리, 앱 포커스 시 다시 가져오기, 화면 포커스 시 새로 고침 등의 기능을 활용하여 앱의 성능과 사용자 경험을 향상시킬 수 있습니다.









