react-query의 success, error, loading과 핸들링

현재 하고있는 프로젝트는 간단한 SPA 커뮤니티의 구현이며
next.js 프로젝트 생성은 create-next-app을 이용하였고
react-query의 useQuery를 이용한 성공,에러,로딩 각 상황의 핸들링을 적용했다.


/user/logout 페이지 진입 시

const { data, isLoading, isError } = useQuery('logout', logoutApi);

위와 같은 코드로 queryKey가 'logout'인 쿼리를 생성한다.
useQuery는 옵션을 주지 않으면 생성과 동시에 두 번째 인자로 전달한 콜백함수를 실행하여 정보를 채우기 시작한다.
일반적으로 get 요청에서 쓰인다.

export const logoutApi = async () => {
  await delay(1000);
  // return { success: '로그아웃 성공' };
  throw Error('Error');
};

export const delay = (time: number) =>
  new Promise((resolve) => {
    setTimeout(() => resolve('delay종료'), time);
  });

setTimeout은 Promise 객체를 반환하지 않기 때문에 await을 이용하여 딜레이 후 다음 코드를 실행할 수 없다.
따라서 delay 함수를 만들어 주고 logoutApi에 적용하여
1초 에러를 던지도록 했다.

따로 옵션을 설정하지 않으면
데이터 요청을 기본적으로 3번 하고 실패하면 에러로 처리한다.
세 번의 요청 후 에러처리되었고 에러페이지로 접근되었다.


로딩의 경우

  if (isLoading) {
    return <CircularProgress size={300} />;
  }

위와 같이 처리하였으며 로딩중일 때 정상동작한다.
심심하지 않게 mui의 CircularProgress를 이용하였다.


성공의 경우는 위에있는 LoginApi의 throw Error 부분
주석을 해제하고 실행하였다.

로그아웃에 성공하고 홈으로 1초 후 홈으로 이동하게 구현하였다.
'logout'쿼리의 값은 로그아웃이 성공하고 난 후 더 이상 필요가 없다고 판단해서 queryClient에서 'logout'을 키로 갖는 쿼리를 removeQueries 함수로 제거하였다.
useEffect의 return은 Unmount 될 때 실행되므로 로그아웃 페이지의 useEffect의 return에 콜백함수로 쿼리 제거코드를 넣었다.
확인을 위해 로그아웃 페이지에서

queryClient.getQueryData('logout');

위 코드를 콘솔로 찍고
같은 코드를 홈 화면에 임시로 구현한 버튼의 onClick 이벤트에서 콘솔로 찍게 하여 확인하였다.
결과 로그아웃페이지에서는 데이터가 찍히고
홈 화면에서 찍어보니 undefined가 찍혔다.
logout과 같이 사용하지 않는 값을 계속 갖고있기 보다는
바로 제거하는게 더 낫다고 판단했다.

성공 화면의 상단에 mui의 progressbar도 적용하여 심심하지 않게 구현했다..

react-query의 캐싱과 데이터재사용, refetch가 강점이라고 하는데 아직 이를 테스트해보지는 않았다.
fresh와 stale한 데이터일 경우를 만들어 refetch해서 새 데이터로 갈아끼우는 것도 추후에 진행해 봐야겠다


로그인페이지의 전체 코드는 다음과 같다

import { delay, getMyInfo, logoutApi } from '@utils/functions';
import { Button, Result } from 'antd';
import { useRouter } from 'next/router';
import { useQuery, useQueryClient } from 'react-query';
import 'antd/dist/antd.css';
import { CircularProgress, LinearProgress } from '@mui/material';
import { useEffect } from 'react';

const Logout = () => {
  const { data, isLoading, isError } = useQuery('logout', logoutApi);
  console.log(isLoading);
  const router = useRouter();
  const queryClient = useQueryClient();
  useEffect(() => {
    return () => queryClient.removeQueries('logout');
  }, []);
  if (isLoading) {
    return <CircularProgress size={300} />;
  }
  if (isError) {
    return (
      <Result
        status="error"
        title="Submission Failed"
        subTitle="Please check and modify the following information before resubmitting."
        extra={[
          <Button type="primary" key="console">
            Go Console
          </Button>,
          <Button key="buy">Buy Again</Button>,
        ]}
      ></Result>
    );
  }
  if (data?.success) {
    (async () => {
      await delay(1000);
      queryClient.removeQueries('user');
      router.push('/');
    })();
    return (
      <>
        <LinearProgress />
        <Result
          status="success"
          title={
            <>
              <p>로그아웃 되었습니다!</p>
            </>
          }
          subTitle={
            <>
              <p> 잠시 후 홈으로 이동합니다</p>
            </>
          }
        />
      </>
    );
  }
};
export default Logout;

로딩과 성공 페이지는 얼추 꾸며놨는데 에러쪽은 antd에서 라이브데모로 구현해놓은 코드를 그대로 가져다 썻다.

좋은 웹페이지 즐겨찾기