본문 바로가기

Frontend Study - 2/React

React : React-Query : useQuery ajax 서버 통신의 응용

ajax를 통해 데이터를 받을 때, 다양한 기능을 추가할 수 있다.

성공 / 실패시에 특정한 일을 하도록 할 수 있고, 몇 초마다 자동으로 요청을 하게 할 수 있게 하는 것.

React-Query의 useQuery를 통해서 쉽게 할 수 있다.

 

그리고 useQuery의 가장 특징 중 하나는 캐싱이 된다는 것!!

 

useQuery를 통해 데이터를 불러올 때 옵션으로 staletime과 cachetime을 보낼 수 있다.

이 둘을 잘 구별해야 한다.

 

* 공식문서

  • staleTime: number | Infinity
    • Optional
    • Defaults to 0
    • The time in milliseconds after data is considered stale. This value only applies to the hook it is defined on.
    • If set to Infinity, the data will never be considered stale
  • cacheTime: number | Infinity
    • Defaults to 5 * 60 * 1000 (5 minutes) or Infinity during SSR
    • The time in milliseconds that unused/inactive cache data remains in memory. When a query's cache becomes unused or inactive, that cache data will be garbage collected after this duration. When different cache times are specified, the longest one will be used.
    • If set to Infinity, will disable garbage collection

 

stale 하다는 것은 말 그대로 신선하다는 것이다. 처음 서버에 데이터를 요청했을 때 데이터는 stale하겠지만,

이후 외부 요청으로 데이터가 변경 되었다면 이전에 받아온 데이터는 낡은 데이터가 되는 것. 

 

- staletime : 전달받은 데이터는 리액트 쿼리의 자료구조 내용 중 캐시에 저장이 된다. 이때 이 캐시데이터의 "신선한 상태" 가 언제까지 될 지를 말해주는 옵션이다. default 값은 0이다. 즉 받아오는 즉시의 상태가 stale하다고 판단하며 캐싱 데이터와 무관하게 계속해서 feching을 진행한다.

 

- cachetime : 캐시 구조에 저장된 데이터는 메모리상에 존재하게 된다. 이 때, 메모리에 저장되어 있는 캐시 데이터가 언제까지 유지될지를 말해주는 옵션이다. 즉, 캐싱된 쿼리의 결과값은 계속 유지되는 것이 아니라 시간이 지나면 메모리에서 사라진다. 쉽게 말해 contextAPI에 빗대자면 Provider의 value 내부에 저장된 객체내부 구조에서 존재했다가 사라지는 것과 비슷한 현상이다. default는 5분이다.

 

 

 

React-Query는 자동으로 재 요청하는 것을 주요 기능으로

SNS / 코인거래소와 같이 실시간 정보들이 중요한 곳에서 주로 사용되고 있다.

 

1. 설치

 npm install react-query

 

 

2. 세팅

Import 해오고 queryClient 선언하고 QueryClientProvider로 감싸주기

 

import { QueryClient, QueryClientProvider } from 'react-query';

const queryClient = new QueryClient();

const root = ReactDOM.createRoot(document.getElementById('root'));
root.render(
  <QueryClientProvider client={QueryClient}>
    <ThemeProvider theme={{ theme }}>
      <GlobalStyle />
      <Router />
    </ThemeProvider>
  </QueryClientProvider>
);

 

 

3. 사용하기

기존의 fetch 사용과 비슷하다. 다만 useQuery안에 작명한 이름과 함께 넣어주고, 변수에 넣어준다.

useQuery를 사용했다면 그 변수에는 다양한 method들이 담기게 된다.

 

.isLoading은, 로딩중일 때의 값을 true로 내보내주고,

.error는 에러가 났을 때 true,

.data는 데이터를 받아왔을 때 true값을 환산한다.

function App(){
  let result = useQuery('key', ()=>
    axios.get('https://testserver.json')
    .then((response)=>{ return response.data })
  )

  return (
    <div>
      { result.isLoading && 'Loading' }
      { result.error && 'Error' }
      { result.data && result.data.name }
    </div>
  )
}

위 소스의 결과값은

데이터를 받아오는 중일 때는 '로딩중'이 출력되고,

에러가 생기면 '에러남',

데이터를 받아왔을때는 data.name 이 출력된다.

 

 

또 useQuery를 사용하면 지속적으로 refetch가 일어난다.

예를 들면 다른 창을 갔다가 다시 내가 보던 창으로 focus 했을 경우 fetch가 일어난다.

너무 자주 된다 싶으면 staleTime이라는 값을 통해서 텀을 조정해 줄 수 있다. 

 

function App(){
  let result = useQuery('key', ()=>
    axios.get('https://testserver.json')
    .then((response)=>{ return response.data }), {staleTime : 1000}
  )

  return (
    <div>
      { result.isLoading && 'Loading' }
      { result.error && 'Error' }
      { result.data && result.data.name }
    </div>
  )
}

이렇게 하면 2초 동안은 refetch가 일어나지 않는다. 혹은 refetch기능을 끌 수 도 있다.

 

+ 추가로 요청 실패 했을 때에도 자동으로 친절하게 retry 해준다.

 

+ fetch를 통해 받아온 데이터를 부모와 자식컴포넌트에서 모두 써야 하는 경우,

기존에는 부모에서 fetch로 받고 props로 자식에게 전달해 주었는데 useQuery를 이용하면 부모, props없이 자식 컴포넌트에서 두번 Fetch 해주면된다. 실제로 Fetch가 두번이 일어나지 않고 useQuery가 한번의 작업으로 실행될 수 있도록 한다. 

 

즉 특정 '키' 값으로 요청한 데이터를 서버에 캐싱해두고,

동일 키 값으로 다른 페이지에서 요청이 들어오면 캐싱해 둔 데이터를 보내주는 것. 멋지다!

 

 

 

참고사이트

- 코딩애플 useQuery 강좌

- TanStack 공식사이트

- https://velog.io/@chltjdrhd777/React-Query-%EC%BA%90%EC%8B%B1%EC%97%90-%EB%8C%80%ED%95%9C-%EA%B5%AC%ED%98%84