[항해 실전 프로젝트][React] useMutation을 이용하여 로딩페이지 보여주기

Carrie·2023년 8월 31일
0

유저가 이미지를 업로드할 때 이미지가 서버에 전송되고 실제 화면에 표시되기까지 약간의 시간이 걸린다. 유저의 사용성 개선을 위해 이 대기 시간 동안 로딩페이지를 보여주려고 한다.

기존의 이미지 업로드 핸들러

// MyPage.jsx
const imageSubmitHandler = async (e) => {
    const file = e.target.files[0];
    if (file) {
      const formData = new FormData();
      formData.append('profileUrl', file);
      try {
        const responseData = await updateMyPageProfileImage(formData);
        if (responseData) {
          setProfileImage(responseData);
          setProfileModal(false);
        } else {
          alert('프로필 이미지 등록에 실패했습니다. 잠시 후 다시 시도해주세요.');
        }
      } catch (error) {
        alert('프로필 이미지 등록에 실패했습니다. 잠시 후 다시 시도해주세요.');
        console.error(error);
      }
    }
  };

여기에서 useMutation 훅을 사용하여 isLoadingtrue인 동안 로딩페이지를 보여주는 방식으로 수정을 해보자!

로딩페이지

먼저 로딩스피너 컴포넌트를 만들었다.

// LoadingSpinner.jsx
import React from 'react';
import './LoadingSpinner.css';

const LoadingSpinner = () => {
  return (
    <div className='loading-container'>
    	.
    	.
    	.
    </div>
  );
};

export default LoadingSpinner;

1차 개선

// MyPage.jsx
import { useMutation } from 'react-query';

const mutation = useMutation(updateMyPageProfileImage);

  const imageSubmitHandler = async (e) => {
    const file = e.target.files[0];
    if (file) {
      const formData = new FormData();
      formData.append('profileUrl', file);
      try {
        const responseData = await mutation.mutateAsync(formData);
        if (responseData) {
          setProfileImage(responseData);
          setProfileModal(false);
        } else {
          alert('프로필 이미지 등록에 실패했습니다. 잠시 후 다시 시도해주세요.');
        }
      } catch (error) {
        alert('프로필 이미지 등록에 실패했습니다. 잠시 후 다시 시도해주세요.');
        console.error(error);
      }
    }
  };
.
.
.
{mutation.isLoading ? <LoadingSpinner isLoading={mutation.isLoading} /> : null}

로딩 및 에러 상태를 자동으로 관리해주는 react-query의 useMutation을 사용하였으나, useMutation의 주요 기능 중 하나인 로딩 및 에러 상태관리 기능을 코드에서 활용을 못하고 있다.

// LoadingSpinner.jsx
import PropTypes from 'prop-types';

const LoadingSpinner = ({ isLoading }) => {
  if (!isLoading) return null;
  
  return (
    <div className='loading-container'>
    .
    .
    .
LoadingSpinner.propTypes = {
  isLoading: PropTypes.bool.isRequired,
};

2차 개선

// MyPage.jsx
const mutation = useMutation(updateMyPageProfileImage);

  const imageSubmitHandler = async (e) => {
    const file = e.target.files[0];
    if (file) {
      const formData = new FormData();
      formData.append('profileUrl', file);
      mutation.mutate(formData, {
        onSuccess: (data) => {
          setProfileImage(data);
          setProfileModal(false);
        },
        onError: (error) => {
          alert('프로필 이미지 등록에 실패했습니다. 잠시 후 다시 시도해주세요.');
          console.error(error);
        }
      });
    }
  };
.
.
.
{mutation.isLoading && <LoadingSpinner />}

기존의 코드에서 개선된 점은 아래와 같다.

  1. 기존의 코드에서는 async/await을 사용하여 API호출 후의 응답을 직접 확인하여 그 결과를 처리하였으나, mutation.mutate의 콜백 옵션을 사용하여 결과를 처리하는 방법으로 개선했다.
  2. 기존의 코드에서는 실패 메시지를 표시하는 alert 부분이 두번 중복으로 나타났으나, onError 콜백을 사용하여 중복을 제거하였다.
  3. useMutation 훅을 사용하면서 try-catch 구문이 필요없어져 코드가 간결해졌다.
  4. mutation.isLoading을 사용하여 로딩 상태를 관리할 수 있게 되었다.
  5. 불필요한 props를 제거하였다.
// LoadingSpinner.jsx
const LoadingSpinner = () => {
  return (
    <div className='loading-container'>
    .
    .
    .
profile
Markup Developer🧑‍💻

0개의 댓글