[리액트 마스터 클래스] React Query 사용하여 효율적으로 데이터 관리하기

Carrie·2023년 9월 29일
0

기존 useState와 useEffect를 사용한 코드에서 React Query를 사용하여 좀 더 효율적으로 데이터를 관리할 수 있도록 리팩토링 해보려고 한다.

기존 코드 분석

기존에는 useStateuseEffect를 사용하여 데이터를 가져오고, coins와 loading의 상태를 직접 관리하고 있다.

// 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);
  })();
}, []);

React Query 설정

React Query를 사용하기 위해 먼저 QueryClient를 생성하고, QueryClientProviderApp을 감싸주어, 앱 전체에서 React Query를 사용할 수 있도록 한다.

// index.ts
import { QueryClient, QueryClientProvider } from "react-query";
.
.
.

const queryClient = new QueryClient();

<QueryClientProvider client={queryClient}>
  <App />
</QueryClientProvider>

fecther 함수 생성

api.ts 파일을 생성하여, fetchCoins 함수를 정의한다.

// api.ts
export function fetchCoins() {
  return fetch("https://api.coinpaprika.com/v1/coins").then((response) =>
    response.json()
  );
}

코드 리팩토링

기존 코드를 리팩토링하여 useQuery 훅을 사용하도록 변경하였다.

// Coins.tsx
const { isLoading, data } = useQuery<ICoin[]>("allCoins", fetchCoins);

fetcher 함수와 함께 useQuery를 사용하면 코드를 단순화할 수 있다.

  • useQuery: 데이터 로딩 상태를 자동으로 관리하며, 데이터를 가져오는 작업을 단순화한다.
  • isLoading: 함수가 실행중이라면 true, 종료되면 false값을 리턴한다.
  • data: 함수가 종료되면 해당 함수의 데이터를 data에 저장한다.
  • 캐싱: React Query는 데이터를 자동으로 캐시하여, 화면에 재진입할 때 새로운 api 호출을 방지하고, 캐시된 데이터를 빠르게 불러온다.

추가 리팩토링(Coin.tsx)

Coin.tsx도 동일하게 리팩토링 해보자! 그런데 이번에는 useQuery가 두 개이기 때문에 추가적으로 설정해줘야 할 부분이 있다.

기존 코드 분석

// Coin.tsx
const [info, setInfo] = useState<InfoData>();
const [priceInfo, setPriceInfo] = useState<PriceData>();
const [loading, setLoading] = useState(true);
  
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]);

fecthcer 함수 생성

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

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

코드 리팩토링(Coin.tsx)

// Coin.tsx
const { isLoading: infoLoading, data: infoData } = useQuery<InfoData>(
  ["info", coinId],
  () => fetchCoinInfo(coinId || "")
);
const { isLoading: priceLoading, data: priceData } = useQuery<PriceData>(
  ["price", coinId],
  () => fetchCoinPriceInfo(coinId || "")
);
  • ["info", coinId], ["price", coinId] useQuery는 각각의 고유한 key를 가지고 있어야 하기 때문에, 다른 쿼리와 혼동되지 않도록 key를 각각 설정해준다.
  • { isLoading: infoLoading, data: infoData }, { isLoading: priceLoading, data: priceData } isLoading과 data도 동일한 이름을 갖고 있어 각 쿼리의 로딩 상태와 데이터를 각각 따로 관리할 수 있도록 위와 같이 설정해준다.
profile
Markup Developer🧑‍💻

0개의 댓글