데이터를 효율적으로 가져오고
, 캐싱
하며 동기화하는 데 도움을 주는 라이브러리다.데이터 동기화
, 데이터 리프레시
, 오류 처리
등의 복잡한 작업을 훨씬 간결하게 처리할 수 있다.// 기존 코드 예시
const Coins = () => {
const [coins, setCoins] = useState<ICoin[]>([]);
const [loading, setLoading] = useState(true);
useEffect(() => {
let isIgnore = false;
(async () => {
const response = await fetch('https://api.coinpaprika.com/v1/coins');
const json = await response.json();
if (!isIgnore) {
setCoins(json.slice(0, 100));
setLoading(false);
}
})();
return () => {
isIgnore = true;
};
}, []);
// 렌더링 로직
};
npm i @tanstack/react-query
import { QueryClient, QueryClientProvider } from '@tanstack/react-query';
const queryClient = new QueryClient();
function App() {
return (
<ThemeProvider theme={theme.light}>
<QueryClientProvider client={queryClient}>
<GlobalStyle />
<RouterProvider router={router} />
</QueryClientProvider>
</ThemeProvider>
);
}
export default App;
const Coins = () => {
const { isLoading, data } = useQuery(['allCoins'], fetchCoins);
/* 아래 코드는 모두 삭제된다. */
// const [coins, setCoins] = useState<CoinInterface[]>([]);
// const [loading, setLoading] = useState(true);
// useEffect(() => {
// let isIgnore = false;
// (async () => {
// const response = await fetch('https://api.coinpaprika.com/v1/coins');
// const json = await response.json();
// if (isIgnore) {
// setCoins(json.slice(0, 100));
// setLoading(false);
// }
// })();
// return () => {
// isIgnore = true;
// };
// }, []);
// api fetcher 파일
export const fetchCoins = () => {
return fetch('https://api.coinpaprika.com/v1/coins').then((response) =>
response.json(),
);
};
const { isLoading, data } = useQuery(['allCoins'], fetchCoins);
import { Link } from 'react-router-dom';
import { useQuery } from '@tanstack/react-query';
import { fetchCoins } from '@/api/fetcher';
import * as S from './styles';
interface ICoin {
id: string;
name: string;
symbol: string;
rank: number;
is_new: boolean;
is_active: boolean;
type: string;
}
const Coins = () => {
const { isLoading, data } = useQuery<ICoin[]>(['allCoins'], fetchCoins);
return (
<S.Container>
<S.Header>
<S.Title>Coins</S.Title>
</S.Header>
{isLoading ? (
<S.Loader>Loading...</S.Loader>
) : (
<S.CoinsList>
{data?.slice(0, 100).map((coin) => (
<S.Coin key={coin.id}>
<Link to={`/${coin.id}`} state={coin}>
<S.Img
src={`https://coinicons-api.vercel.app/api/icon/${coin.symbol.toLowerCase()}`}
/>
<span>{coin.name}</span>
<span>→</span>
</Link>
</S.Coin>
))}
</S.CoinsList>
)}
</S.Container>
);
};
export default Coins;
useState와 useEffect로 상태를 관리하고 데이터를 호출하던 로직을 react query를 통해 한번에 해결할 수 있다.
💡 React Query는데이터를 자동으로 캐싱
하므로 동일한 요청을 여러 번 수행할 필요가 없다.
const { isLoading: infoLoading, data: infoData } = useQuery<IInfoData>(
['info', coinId],
() => fetchCoinInfo(coinId.coinId),
);
const { isLoading: tickersLoading, data: tickersData } = useQuery<IPriceData>(
['tickers', coinId],
() => fetchCoinTickers(coinId.coinId),
);
const loading = infoLoading || tickersLoading;
캐싱된 쿼리
와 관련된 정보
를 시각적으로 확인할 수 있게 도와주는 도구다.npm i @tanstack/react-query-devtools
import router from './router';
import { RouterProvider } from 'react-router-dom';
import { QueryClient, QueryClientProvider } from '@tanstack/react-query';
import { ReactQueryDevtools } from '@tanstack/react-query-devtools';
import { ThemeProvider } from 'styled-components';
import GlobalStyle from './styles/GlobalStyle';
import theme from '@/styles/theme';
const queryClient = new QueryClient();
function App() {
return (
<ThemeProvider theme={theme.light}>
<QueryClientProvider client={queryClient}>
<GlobalStyle />
<RouterProvider router={router} />
<ReactQueryDevtools initialIsOpen={false} />
</QueryClientProvider>
</ThemeProvider>
);
}
export default App;
Devtools는 개발 모드에서만 번들에 포함되므로, 프로덕션 빌드 중에 제외하는 것에 대해 걱정할 필요가 없다.