React Native로 앱을 만들다 보면 외부 API에서 데이터를 가져오거나 서버에 데이터를 저장하는 일이 자주 발생합니다. 이때 단순히 
fetch 함수만 사용하면, 로딩 상태나 오류 처리, 캐싱 등 여러 번 반복되는 패턴을 매번 직접 구현해야 해서 번거롭습니다.
이를 해결하기 위해 
TanStack Query
를 사용하면 데이터 패칭을 매우 간편하고 안정적으로 처리할 수 있습니다. 이 글에서는 React Native (Expo) 환경에서 TanStack Query를 설치하고 활용하는 방법을 기초부터 차근차근 예제와 함께 안내해 드리겠습니다.
🚀 
TanStack Query란 무엇인가요? 🔗  TanStack Query는 서버에서 가져오는 데이터를 효율적으로 관리할 수 있도록 도와주는 상태 관리 라이브러리입니다. 예전 이름은 React Query였으며, 현재는 다양한 플랫폼을 지원하는 범용 도구로 발전했습니다.
React Native에서도 다음과 같은 상황에서 유용하게 사용할 수 있습니다:
서버에서 받아온 데이터를 캐시하고, 동일한 요청을 중복하지 않도록 할 때 
네트워크 연결 상태나 앱 포커스에 따라 데이터를 자동으로 다시 불러올 때 
에러나 로딩 상태를 자동으로 처리하고 싶을 때 
 
React Native (Expo) 프로젝트에서 TanStack Query를 사용하려면 다음과 같이 설치합니다:
npx  expo  install  @tanstack/react-query npm  i  -D  @tanstack/eslint-plugin-query 
🚀 
QueryClientProvider 설정하기 🔗  설치를 마쳤다면 QueryClient를 만들고, 앱의 최상단 컴포넌트를 QueryClientProvider로 감싸야 합니다.
import  { QueryClient, QueryClientProvider }  from  '@tanstack/react-query' ; const  queryClient  =  new  QueryClient (); export  default  function  App ()  {   return  (     < QueryClientProvider  client ={ queryClient } >       { /* 앱 컴포넌트들 */ }     </ QueryClientProvider >   ); } 이렇게 설정하면 이제부터 앱 전체에서 TanStack Query 기능을 사용할 수 있게 됩니다.
이제 가장 기본적인 사용법부터 살펴보겠습니다. JSONPlaceholder의 사용자 API(/users)를 가져와서 리스트로 표시해보겠습니다.
import  { useQuery }  from  '@tanstack/react-query' ; import  axios  from  'axios' ; import  { FlatList, Text, View }  from  'react-native' ;   
const  fetchUsers  =  async  ()  =>  {  // 정보를 fetch하는 함수   const  res  =  await  axios. get ( 'https://jsonplaceholder.typicode.com/users' );   return  res.data; };   
export  default  function  UserList ()  {   const  {  data ,  isLoading ,  isError ,  error  }  =  useQuery ({     queryKey: [ 'users' ],  // 쿼리의 고유 식별자     queryFn: fetchUsers,  // 정보를 fetch하는 함수   });   
  if  (isLoading)  return  < Text >불러오는 중...</ Text >;   
  if  (isError)  return  < Text >오류 발생:  { (error  as  Error ).message } </ Text >;   
    return  (     < FlatList       data ={ data }       keyExtractor ={ ( item )  =>  item.id. toString () }       renderItem ={ ({  item  })  =>  < Text > { item.name } </ Text > }     />   ); } 
queryKey는 요청을 구분하고 캐시를 적용하는 데 매우 중요한 역할을 합니다. 배열 형태로 작성하며, 특정 파라미터에 따라 다르게 구성할 수 있습니다.
useQuery ({   queryKey: [ 'user' , userId],   queryFn : ()  =>  fetchUser (userId), }); 여기서 userId가 다르면 다른 쿼리로 인식되어 각기 다른 캐시를 사용하게 됩니다.
앱이 포커스를 얻을 때 자동으로 쿼리를 다시 실행하고 싶다면 AppState와 focusManager를 사용합니다:
import  { useEffect }  from  'react' ; import  { AppState, Platform }  from  'react-native' ; import  { focusManager }  from  '@tanstack/react-query' ; function  onAppStateChange ( status ) {   if  (Platform. OS  !==  'web' ) {     focusManager. setFocused (status  ===  'active' );   } } useEffect (()  =>  {   const  subscription  =  AppState. addEventListener ( 'change' , onAppStateChange);   return  ()  =>  subscription. remove (); }, []); 🚀 
React Navigation과 화면 포커스 시 refetch 🔗  React Navigation에서는 useFocusEffect를 활용하여 화면에 들어올 때 데이터를 갱신할 수 있습니다:
import  { useFocusEffect }  from  '@react-navigation/native' ; import  { useCallback }  from  'react' ;   
export  function  useRefreshOnFocus ( refetch ) {   useFocusEffect (     useCallback (()  =>  {       refetch ();     }, [])   ); } 서버에 데이터를 등록하거나 수정할 때는 useMutation을 사용합니다. 아래는 게시글을 추가하는 예시입니다:
import  { useMutation, useQueryClient }  from  '@tanstack/react-query' ; import  axios  from  'axios' ;   
const  createPost  =  async  ( newPost )  =>  {   const  res  =  await  axios. post ( 'https://jsonplaceholder.typicode.com/posts' , newPost);   return  res.data; };   
export  function  NewPostButton () {   const  queryClient  =  useQueryClient ();  // 쿼리 클라이언트 인스턴스   const  mutation  =  useMutation ({     mutationFn: createPost,  // 뮤테이션 함수     onSuccess : ()  =>  {       queryClient. invalidateQueries ({ queryKey: [ 'posts' ] });  // 쿼리 데이터 무효화     },   });   return  (     < Button       title = "새 글 작성"       onPress ={ ()  =>  mutation. mutate ({ title:  '제목' , body:  '내용'  }) }  // 뮤테이션 실행     />   ); } 
🚀 
React Native에서 Devtools 사용 🔗  웹과는 달리 React Native에서는 Devtools를 바로 사용할 수는 없습니다. 다음과 같은 도구를 통해 쿼리 상태를 확인할 수 있습니다:
다음 명령어로 플러그인을 설치합니다.
npx  expo  install  @dev-plugins/react-query 플러그인을 사용하려면 다음과 같이 설정해야 합니다.
import  { QueryClient, QueryClientProvider }  from  '@tanstack/react-query' ; import  { useReactQueryDevTools }  from  '@dev-plugins/react-query' ;   
const  queryClient  =  new  QueryClient ({});   
export  default  function  App ()  {   useReactQueryDevTools (queryClient);  // 디버깅 도구 초기화   
  return  (     < QueryClientProvider  client ={ queryClient } >       { /* ... */ }     </ QueryClientProvider >   ); } 이제 앱을 실행한 터미널에서 shift + M 키를 눌러 Open @dev-plugins/react-query 를 선택하면 웹 브라우저에서 디버깅 도구를 열 수 있습니다.
React Native (Expo)에서 TanStack Query를 사용하면 데이터 패칭, 캐싱, 에러 처리, 상태 관리 등을 매우 간단하고 효율적으로 구현할 수 있습니다. 특히 모바일 환경에서는 네트워크 연결 상태나 앱 포커스에 따라 데이터 동기화를 자동으로 처리하는 기능이 매우 유용합니다.
이번 포스팅을 통해 기초부터 실전 사용까지 예제와 함께 익히셨기를 바랍니다.