React Query란 React 애플리케이션에서 서버 state를 fetching, caching, synchronizing, updating할 수 있도록 도와주는 라이브러리다.
react 버전이 18이면 타입스크립트에서 react query를 못 불러온다.
npm i @tanstack/react-query 를 입력해서 모듈을 설치해주자.
npm i -D @tanstack/react-query-devtools 이것도
그리고 @tanstack/react-query에서 useQuery를 사용할때 query key의 값은 대괄호로 묶어줘야한다
예시
js const { isLoading, data } = useQuery(["allCoins"], fetchCoins);
설치
npm i react-query로 터미널에 설치해준다.
index 페이지에 다음과 같이 추가해준다.
import { QueryClient , QueryClientProvider} from "react-query";
const queryClient = new QueryClient()```
다음 render쪽에 가서 감싸준다.
```js
root.render(
<QueryClientProvider client={queryClient}>
<ThemeProvider theme={theme}>
<App />
</ThemeProvider>
</QueryClientProvider>
);
그래서 React-Query를 어떻게 쓸것이냐
일단 api를 컴포넌트와 다른곳에 모아두는 작업부터 시작하자.
Coins에 있는 coin정보를 가져오는 fetch구문을 따로 src/api.ts 옮겨놨다.
export async function fetchCoins() {
return await (await fetch("https://api.coinpaprika.com/v1/coins")).json();
}
다음 coins 파일의 function Coins 아래에
const {isLoading, data} = useQuery("allCoins", fetchCoins)
react-query 라이브러리의 useQuery Hook을 이용하여 다음과 같이 작성해 주었다.
어디서 많이 보던 구문 아닌가. 그렇다 왼쪽은 Loading을 담당하던 useState에서 많이 보던 그것이다.
저 구문의 뜻은 useQuery hook은 fetcher 함수를 부르고 fetcher 함수가 loading중이라면 react query는 그걸 알려줄거다.
기존 코드
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);
})();
}, []);
React-query로 정리된 코드
const { isLoading, data } = useQuery<ICoin[]>(["allCoins"], fetchCoins);
와 이거참 ....
기존 코드에서 100개의 코인목록만 보여주는 setCoins(json.slice(0,100)); 는
data?.slice(0, 100)로 대체됬다 정말 멋져
또 react-query의 특징은 페이지 정보를 cache 해놓기 때문에 Loading을 매번보지 않아도 된다.
api에 매번 접근하지 않는다는것이다.
App.tsx 페이지에 import { ReactQueryDevtools } from "react-query/devtools"를 설치해주고
return (
<>
<GlobalStyle />
<Router />
<ReactQueryDevtools initialIsOpen={true} />
</>
);
이렇게 코드를 작성해준다 그러면
리액트 화면에 다음과 같은 인터페이스가 생길건데 저 devtool에서현재 페이지가 가지고 있는 cathe가 무엇인지 확인 가능하다.
이제 Coin.tsx 페이지를 바꿔줄건데 Coins 페이지와 큰 차이는 없다
const { isLoading: infoLoading, data: infoData } = useQuery<InfoData>(
["info", coinId],
() => fetchCoinInfo(coinId)
);
const { isLoading: tickersLoaidng, data: tickersData } = useQuery<PriceData>(
["tickers", coinId],
() => fetchCoinTickers(coinId)
);
여기서는 InfoData와 PriceData가 필요한데
둘의 useQuery 구문에 2개의 query를 사용할시 같은 이름으로 사용할수 없다 그래서
isLoading: infoLoading , Date도 마찬가지로 data:infodata 로 코딩해주었다.
또 [coinId]
코드의 경우엔 react-query에서 캐시를 저장하기위해 고유한 key값이 필요하니
앞에다가 ["info",coinId]
를 넣어 []의 앞은 카테고리 뒤는 각자 고유의 key값을 주었다.
return부분에서
js const loading = infoLoading || tickerLoading;
으로 설정해 주니
기존에 사용하던 loading도 오류없이 작동한다.