[ useQuery ] - custom hook 을 useQuery로 바꿔보자 -1

슬로그·2023년 7월 20일

ReactQuery

목록 보기
1/3
post-thumbnail

☝🏻 customhook

데이터를 받아오는 custom hook을 만들어서 다른 컴포넌트에 api를 fetch하는 커스텀훅을 받아온다고 가정해보자.
커스텀훅에서 만들었던 logding , error , data 라는 상태값을 내가 원하는 컴포넌트에서 호출하게 되고, 동일하게 데이터를 받는 로직을 실행하게 될것이다.

만약 브라우저에 커스텀훅을 받아온 한개의 컴포넌트가 2개 나열되어있어야 한다면 console로 확인해 봤을때 컴포넌트안에 커스텀훅의 데이터가 두번씩 출력되는걸 확인 할 수 있다.

☝🏻 커스텀 훅을 만들어 데이터를 받아왔을때 문제점 ?

  • 커스텀훅에서 만든 상태값은 전역적으로 재사용하거나 캐싱하기 위한 별도의 로직이 담겨있지않다.

  • 커스텀훅을 호출하는 컴포넌트들 마다 내부 상태들이 다 각각 다르게 설정이되고 , 커스텀훅을 사용할때마다 네트워크 통신이 발생한다.

그래서 서버 상태 가져오기 , 캐싱 을 보다 쉡기 다룰 수 있도록 도와주는 라이브러리인 리액트 쿼리로 바꿔보자 !

☝🏻 React Query 적용해보기

리액트 쿼리는 쿼리별로 키를 제공한다. 각각 네트워크 통신별로 고유한 키를 제공 하고 키 이름 아래에 데이터를 보관하게 된다.
그래서 우리가 필요할때 불러오면 가지고 있던 메모리 (고유한 키)안에 가지고있던 캐시된 데이터를 제공해주게 된다.
앞에서 말했던 한 컴포넌트를 두번 불러오는 브라우저에서 리액트 쿼리를 사용한다면 고유한 키를 두번 불러와도 우리는 딱 한번만 네트워크 통신이 발생하는걸 볼수 있다.

기본적인 사용법은 리액트 쿼리 공식 사이트를 보면 된다.

1) 리액트 쿼리를 add하고 최상단 컴포넌트에 provider로 내가 보여줄 컴포넌트를 안에 넣어 작성한다.

npm i @tanstack/react-query

	import { useQuery } from "@tanstack/react-query";

2) App.js에서 provider 씌어주기


  import React from 'react';
  import './App.css';
  import MainProducts from './components/MainProducts';
  import { QueryClient, QueryClientProvider } from '@tanstack/react-query';

  const queryClient = new QueryClient();

  export default function App() {
    return (
      <QueryClientProvider client={queryClient}>
        <MainProducts />
      </QueryClientProvider>
    )
  }

3)

	import { useQuery } from '@tanstack/react-query';
	
	export default function Products(){
    	const { data:products, // 2 
               	isLoading, 
               	error } = useQuery([products], async() => {  // 1
			fetch(`data/products.json`)
              .then((res) => res.json());
        }) 1
    }
  1. useQuery 안에 첫번째 인자는 내가 저장해놓을 고유한 이름의 키배열로 전달해줘야한다. (위에서는 'products') 두번째 인수로 가지고와야하는 함수를 전달해준다.
    useQuery를 호출하게 되면 객체들을 리턴 해 주는데 굉장히 많은 키들이 있다. isLoading, error, data 등등 공식문서에서 확인해보고 원하는걸 가져와 주면 된다.
    세번째 함수 인자로는 옵션들이 있는데 이것도 많은 옵션들이 있다.
    네트워크를 가지고오는 로직을 두번째인수에 넣어줄때는 따로 만들어 넣거나 아니면 위에서 처럼 콜백함수로 가져오면 된다.

  2. 이제 내가 가져오고싶은 걸 useQuery안에 객체 구조할당분해로 가져온다.
    보통 data , isLoading(로딩 중인지 아닌지) , error(에러가 났는지 안났는지) 를 많이 사용하는것? 같다. data는 성공시 받아올 데이터를 말하는데 데이터를 다른곳에 사용할 수 있도록 원하는 이름(products)으로 지정해줄수있다.

이렇게 고유한 키를 지정하여 데이터를 저장하게 되고 로딩중일때, 또는 에러가 났을때에 대하여 고유한 키안에 캐싱해두었던 데이터를 가져와 간편하게 사용할수 있다는 장점이 있다.

4) 만약 다른 컴포넌트에서 데이터 조건별로 사용을 달리하고 싶다면 배열 형태로 고유한키들을 추가해줄 수 있다.

	const [checked , setChecked ] = useState(false);

	useQuery(['todos', checked],async() => {
		console.log('fetching...');
      	return fetch(`data/${checked ? 'all_' : ''}products.json`)
      	.then((res) => res.json())
    })

예시로 checked 여부에 따라 다른 데이터를 보여주고 싶다면 useState로 상태값을 만들어주고 useQuery에 checked의 키를 추가해준다. 그리고나서 두번째 데이터를 불러오는 곳에서 checked가 되었다면 다른 내가 원하는 데이터를 받아올 수 있도록 삼항조건 연산자로 수정해주면 된다.

전체코드

	import React, { useState } from "react";
    import useProducts from "../hooks/use-products";
    import { useQuery } from "@tanstack/react-query";

    export default function Products() {
      const [checked, setChecked] = useState(false);
      // const [loading, error, products] = useProducts({ salesOnly: checked }); // 커스텀 훅 
      const handleChange = () => setChecked((prev) => !prev);

      const {
        data: products,
        error,
        isLoading,
      } = useQuery(["products", checked], async () => {
        return fetch(`data/${checked ? "sale_" : ""}products.json`) //
          .then((res) => res.json());
      });

      if (isLoading) return <p>Loading...</p>;

      if (error) return <p>{error}</p>;

      return (
        <>
          <label>
            <input type="checkbox" checked={checked} onChange={handleChange} />
            Show Only 🔥 Sale
          </label>
          <ul>
            {products.map((product) => (
              <li key={product.id}>
                <article>
                  <h3>{product.name}</h3>
                  <p>{product.price}</p>
                </article>
              </li>
            ))}
          </ul>
        </>
      );
    }

✍🏻 custom hook 을 useQuery로 바꿔보자 -2 staleTime과 chacheTime

profile
빨리가는 유일한 방법은 제대로 가는것

0개의 댓글