[React] react-query

오트밀·2022년 2월 10일
0

useQuery

react-query의 useQuery를 사용하면 데이터를 캐시에 저장해서 똑같은 페이지를 다시 들어가면 api를 호출하는 일이 없이 기존의 데이터를 화면에 그대로 뿌려준다.
따라서 쓸모없는 api 호출이 줄어 로딩이 필요없어짐에 따라 데이터 호출비용이 주는 효과가 있다.

Coins.tsx

  const [coins, setCoins] = useState<CoinInterface[]>([]);
  const [loading, setLoading] = useState(true);
  useEffect(() => {
    (async () => {
      const response = await fetch('https://api.coinpaprika.com/v1/coins');
      const json = await response.json();
      setCoins(json.slice(0, 100));
      setLoading(false);
    })();
  }, []); 

Coin.tsx

  const [loading, setLoading] = useState(true);
  const [info, setInfo] = useState<IInfoData>();
  const [priceInfo, setPriceInfo] = useState<IpriceData>();

  useEffect(() => {
    (async () => {
      const infoData = await (
        await fetch(`https://api.coinpaprika.com/v1/coins/${coinId}`)
      ).json();
      const priceData = await (
        await fetch(`https://api.coinpaprika.com/v1/tickers/${coinId}`)
      ).json();
      setInfo(infoData);
      setPriceInfo(priceData);
      setLoading(false);
    })();
  }, [coinId]);

기존에 작성한 코드는 캐시를 사용하지 않고 페이지를 로딩할때마다 데이터를 가져오지만

Coins.tsx

import { fetchCoins } from '../api';

...

  const { isLoading, data } = useQuery<ICoin[]>('allCoins', fetchCoins);
  
  //data 타입이 ICoin[]라는 것을 명시하고 
  //data를 allCoins라는 이름으로 칭한다.
  //fetchCoins함수가 api를 부르기 전에는 isLoading이 동작하고
  //fetchCoins함수가 api를 불러 데이터를 가져오면 allCoins에 데이터를 보여준다.

Coin.tsx

import { fetchInfoData, fetchPriceData } from "../api";

...

  const { isLoading: infoLoading, data: infoData } = useQuery<IInfoData>(
    ["info", coinId],
    () => fetchInfoData(coinId)
  );
  
  const { isLoading: priceLoading, data: priceData } = useQuery<IpriceData>(
    ["tickers", coinId],
    () => fetchPriceData(coinId)
  );
//useQuery는 query key 와 fetcher 함수를 변수로 받는다.
//useQuery의 key는 react query 캐시 시스템에 저장되고 작동하기 위해서는 unique한 값이어야한다.
//따라서 각 api의 key 값을 ["info", coinId], ["tickers", coinId]로 설정한다.   
//기존에는 api들이 데이터를 불러온 후 isloading을 했기때문에 setloading(false);으로 loading의 state를 바꿨지만 
//fetcher function으로 api를 분리시킨후에는 각각의 api에 따로 loading fuction이 존재하므로 이를 구분하기 위해 'infoLoading','priceLoading'이라는 별명을 붙인다.
//data도 혼동을 막기위해 'infoData','priceData'를 붙인다.

api.tsx

const BASE_URL = `https://api.coinpaprika.com/v1`;

export function fetchCoins() {
  return fetch(`${BASE_URL}/coins`).then((response) => response.json());
}

export function fetchInfoData(coinId: string) {
  return fetch(`${BASE_URL}/coins/${coinId}`).then((response) =>
    response.json()
  );
}

export function fetchPriceData(coinId: string) {
  return fetch(`${BASE_URL}/tickers/${coinId}`).then((response) =>
    response.json()
  );
}
//fetch 함수는 반드시 fetch promise를 return 해야한다.

이렇게 fetcher function을 분리하고 useQuery를 적용하면 코드도 더 간단히 정리되고 쓸모없는 api호출을 줄일 수 있다.

https://react-query.tanstack.com/reference/useQuery#_top


devtools

initialIsOpen 속성을 true로하면 아래 사진처럼 react-query가 가지고 있는 캐시를 화면에 보여준다.

App.tsx

import { ReactQueryDevtools } from 'react-query/devtools';
...

function App() {
  return (
    <>
      <GlobalStyle />
      <Router />
      <ReactQueryDevtools initialIsOpen={true} />
    </>
  );
}


https://react-query.tanstack.com/devtools#_top

profile
루틴을 만들자

0개의 댓글