React Query
공식문서에는 아래와 같이 설명되어 있다.
Performant and powerful data synchronization for React
음... 그래. 리액트에 어울리는 동기화 라이브러리 라고 한다. (그래? 한번 써보았다.)
기존 코드
import { useEffect, useState } from "react";
import { Link } from "react-router-dom";
import styled from "styled-components";
import { getCoins } from "APIs/get";
import { useQuery } from "react-query";
//
Styled Component 생략
//
const Coins = () => {
const { isLoading, data } = useQuery<ICoin[]>("allCoins", getCoins, {
select: data => data.slice(0, 30),
});
// 아래 주석 처리된 부분이 모두 위에 것으로 변경되었다.
// const [coins, setCoins] = useState<CoinInterface[]>([]);
// const [loading, setLoading] = useState(true);
// useEffect(() => {
// (async () => {
// const _cutCoins = await getCoins();
// setCoins(_cutCoins);
// setLoading(false);
// })();
// }, []);
return (
<Container>
<Header>
<Title>Coin list</Title>
</Header>
{isLoading ? (
<Loader>loading...</Loader>
) : (
<CoinsList>
{data?.map(coin => (
<Coin key={coin.id}>
<Link to={`/${coin.id}`} state={{ name: coin.name }}>
<Img
src={`https://coinicons-api.vercel.app/api/icon/${coin.symbol.toLocaleLowerCase()}`}
/>
<Text>{coin.name} →</Text>
</Link>
</Coin>
))}
</CoinsList>
)}
</Container>
);
};
export default Coins;
눈여겨 볼 점
const { isLoading, data } = useQuery<ICoin[]>("allCoins", getCoins, {
select: data => data.slice(0, 30),
});
isLoading
API 로딩 중 boolean type data
data
return 받은 API data (*json Type으로 넘겨주는 것이 일반적(권장, 필수아님))
"allCoins"
Query-key 로 전체 프로젝트에 같은 이름이 있으면 안됨.
getCoins
API call Function Name
*원칙적인 사용은 아래와 같은데, 위와 같이 축약해서 사용하는 것이다.
const { isLoading, error, data } = useQuery({
queryKey: ['repoData'],
queryFn: () =>
fetch('https://api.github.com/repos/tanstack/query').then(res =>
res.json()
)
})
장점
1. React-Query가 적용된 API는 cache 되는 것을 볼 수 있다. 불필요한 API호출이 없어진다.
여기서 질문이 생긴다. 그럼 저장되는 Data는 어디에 보관되는 걸까? 잘 모르겠다.
내가 확인한 바로는, Recoil 처럼 Browser 내 Storage를 사용하는 것은 아닌 것 같다.
이 부분을 확인하려 공식문서를 찾아봤다. 흠... 첫 문장부터 답이 나온다. 어딘가에 숨겨두고 있는 것으로 추정된다.
- Is persisted remotely in a location you do not control or own
- Requires asynchronous APIs for fetching and updating
- Implies shared ownership and can be changed by other people without your knowledge
- Can potentially become "out of date" in your applications if you're not careful
- 귀하가 통제하거나 소유하지 않는 위치에 원격으로 유지됩니다.
- 가져오기 및 업데이트를 위한 비동기 API가 필요합니다.
- 공유 소유권을 암시하며 사용자 모르게 다른 사람이 변경할 수 있음
- 주의하지 않으면 응용 프로그램에서 잠재적으로 "구식"이 될 수 있습니다.
단점
아직 못찼았다.
기타 특징
useQueries
useQuery 말고 useQueries 라는 것도 있다.
Promise.all 하고 비슷하게 동작한다. 배열로 useQuery 실행 결과 값들을 리턴해준다. (병렬 비동기 처리를 하기 위해 사용)
보통 api 호출 값이니까 isLoading, data,... 등등을 배열로 묶어서 받게 된다고 보면된다.
그러나, 과연 좋은지는 의문이다.
노마드코더 니코 같은 경우는, useQuery를 2개 사용하고, 각 loading 값을 아래와 같이 선언해서 단축평가를 받도록 처리했다.
const isLoading = infoLoading || tickersLoading;
내가 보기에도 오히려 이 방식이 더 적합해보인다.
참고2. 에서는 동적 렌더링이 필요할 때만, useQueries를 사용하는 것을 권장했다. (이건, 필요한 API 연동 포인트가 있을 때 좀 더 고민해 봐야겠다.
추가로 더 작업하면서 알게되는 내용은 추가하도록 한다.
참고
1. https://react-query-v3.tanstack.com/overview#motivation
2. https://jforj.tistory.com/245
댓글