react-query

지렁·2024년 3월 22일

커피챗 리스트 페이지

  • react-query 적용
  • loading 처리

react-qeury

  • 간단 설명
import { useQuery } from 'react-query';
const { data, isLoading, error } = useQuery(queryKey, queryFn?, queryOption);

useQuery는 두번째 패러미터로 전달받은 query function을 실행시켜주고 이 query function의 상태에 따른 여러 값을 객체로 리턴해주는 hook이다.
query function은 데이터를 불러오는 비동기 함수로, Promise를 리턴해야 한다.
isLoading은 query function이 실행이 끝나지 않았다면 true, 끝났다면 false가 된다.
data는 query function에서 마지막으로 resolve된 값이다. 따라서 async, await, state를 모두 사용해 Promise의 결과값을 가져오는 방식보다 코드가 간단해진다.
error는 query function에서 에러가 throw된 경우 그 에러가 된다

🟣 도입 전

currentPage, sortData, 검색어 값이 달라질 때마다 fetchCoffeeData을 실행하도록 useEffect 문에 작성

그리고 로딩과 에러 처리를 위해 각각의 state을 만들어준 후 api요청으로 data를 잘 받아왔을 때 loading,error 상태를 변경해주었다

const useFetchCoffeeData = (currentPage, sortData, 검색어) => {
  const [coffeeData, setCoffeeData] = useRecoilState(coffeeChatListState);
  const [loading, setLoading] = useState(false);
  const [error, setError] = useState(null);

  useEffect(() => {
    const fetchCoffeeData = async () => {
      setLoading(true);
      try {
        const data = await getCoffeeChat(
          currentPage - 1,
          sortData.pageSize || 12,
          sortData.sort,
          sortData.jobCategory,
          검색어,
        );
        setCoffeeData(data.data.data);
        setError(null);
      } catch (error) {
        setError(error);
        setCoffeeData(null);
      } finally {
        setLoading(false);
      }
    };

    fetchCoffeeData();
  }, [currentPage, sortData, 검색어]);

  return { coffeeData, loading, error };
};

export default useFetchCoffeeData;

🟣 도입 전

useQuery를 통해 간단하게 currentPage, sortData, 검색어 값이 달라질 때마다 fetchCoffeeData을 실행하는 기능을 구현하였다

isLoading과 error를 쉽게 적용할 수 있다!

const useFetchCoffeeData = (currentPage, sortData, 검색어) => {
  const fetchCoffeeData = async () => {
    const response = await getCoffeeChat(
      currentPage - 1,
      sortData.pageSize || 12,
      sortData.sort,
      sortData.jobCategory,
      검색어,
    );
    return response.data.data;
  };

  const {
    data: coffeeData,
    isLoading,
    error,
  } = useQuery(['coffeeData', currentPage, sortData, 검색어], fetchCoffeeData);

  return { coffeeData, isPending, isLoading, error };
};

export default useFetchCoffeeData;

loading 처리

메인페이지, 회사 전체 페이지에서는 Skeleton UI를 적용하였지만 이미지가 없는 커피챗 페이지에서는 loading-spinner이 더 적절하지 않을까~? 싶은 생각으로 적용해보았다

문제 발생

필터,검색어,페이지 값의 변화가 생길 때마다 데이터 fetch 가 다시 되도록 설계되었는데 loading 값에 따라 loading spinner가 동작하지 않는다

useFetchCoffeeData.jsx

 const fetchCoffeeData = async () => {
    const response = await getCoffeeChat(
      currentPage - 1,
      sortData.pageSize || 12,
      sortData.sort,
      sortData.jobCategory,
      검색어,
    );
    return response.data.data;
  };

const {
    data: coffeeData,
    isLoading: loading,
    error,
  } = useQuery(
    ['coffeeData', currentPage, sortData, 검색어],
    fetchCoffeeData, 
    {
      keepPreviousData: true,
    },
  );

  return { coffeeData, isPending, isLoading, error };
};

CoffeeListComponent.jsx

위의 데이터 fetching 훅으로 받아온 data, isLoading 값을 여기서 사용해주었다
isLoaidng일 때 Loading 컴포넌트(loading-spinner)를 리턴하도록 의도하였지만 첫 렌더링 시에만 작동되고 그 후에 필터,검색어,페이지 값이 달라질 때는 loaidng 컴포넌트가 작동하지 않았다

function CoffeeListComponent({ jobCategories, sortData, 검색어 }) {
  const pageNum = JSON.parse(localStorage.getItem('page')) || 1;
  const [currentPage, setCurrentPage] = useState(pageNum);
  const { coffeeData, isLoading } = useFetchCoffeeData(currentPage, sortData, 검색어);

  if (isLoading) {
    return <Loading />;
  }

  return (
    <>
      <Grid container spacing={{ xs: 2, md: 2 }}>
        {coffeeData?.content?.length > 0 &&
          coffeeData.content.map((item, index) => (
            <Grid item xs={12} sm={6} md={6} key={index}>
              <CoffeeChatCard data={item} kindOfJd={jobCategories} />
            </Grid>
          ))}
      </Grid>
      <CoffeePagenation
        currentPage={currentPage}
        setCurrentPage={setCurrentPage}
        coffeeData={coffeeData}
      />
    </>
  );

문제의 원인은 이 옵션이었다! 직역= "이전데이터를 유지할까? 네!"

해당 옵션을 지우니 Loaindg 컴포넌트가 fetching 될 때마다 잘 실행된다!

  {
      keepPreviousData: true,
    },
profile
공부 기록 공간 🎈💻

0개의 댓글