[42gg] 에러 페이지 구현하기

Daehyun·2022년 7월 31일
1

42gg

목록 보기
6/8
post-thumbnail

이번에는 에러페이지를 구현하게 되었다.
axios 데이터 요청 시 발생하는 문제들, 잘못된 url나 의도적으로 query문을 넣어 접근하는 문제 등을 에러페이지로 넘겨주었다.
더불어 에러는 아니지만, 사용자가 입력을 잘못하거나 의도치 않은 동작을 실행하는 경우 alert창을 띄워 예기치 못한 문제를 막아주는 부분도 추가해주었다.


0. 에러페이지

  • 우선 에러가 발생할 경우 띄워줄 페이지를 먼저 만들어주었다.

    import React, { useEffect } from 'react';
    import { useRouter } from 'next/router';
    import { useRecoilState } from 'recoil';
    import { errorState } from 'utils/recoil/error';
    import styles from 'styles/Error.module.scss';
    
    export default function ErrorPage() {
     const [errorMessage, setErrorMessage] = useRecoilState(errorState);
     const router = useRouter();
    
     useEffect(() => {
       router.replace(`/`);
     }, []); // 에러페이지로 넘어오면 url을 초기화시켜준다.
    
     const goHome = () => {
       setErrorMessage('');
       router.push('/');
     }; // 홈 버튼을 누르면 에러메시지를 초기화하고 메인페이지로 이동시킨다.
    
     return (
       <div className={styles.container}>
         <div className={styles.errorContainer}>
           <div className={styles.title}>42GG</div>
           <div className={styles.errorMessage}>
             {errorMessage === 'DK404' // 404 NotFound의 경우 별도로 처리해준다.
               ? '잘못된 요청입니다!'
               : '데이터 요청에 실패하였습니다.'}
             <div className={styles.errorCode}>({errorMessage})</div>
           </div>
           <div className={styles.home} onClick={goHome}>
             <div className={styles.positive}>
               <input type='button' value='🏠 홈으로 🏠' />
             </div> // 홈버튼을 만들어 메인페이지로 이동하게 해준다.
           </div>
         </div>
       </div>
     );
    }
  • 잘못된 접근과 서버에서 데이터를 불러오지 못한 경우 기본적으로 에러페이지로 이동시켜주며, url을 초기화시켜준다. 또한 뒤로가기보다는 홈 버튼을 눈에 띄게 해주어 사용자가 메인페이지로 이동할 수 있도록 해주었다.

  • 리코일을 사용하여 errorMessage를 설정해주면 에러페이지로 이동하게 구현해주었다. 에러페이지를 빠져나가면 errorMessage를 빈 문자열로 바꾸어 정상적으로 동작함을 알려준다.

  • 에러페이지는 다음과 같이 보여진다.

1. 에러 상태 관리

  • 에러페이지의 이동은 errorMessage의 상태를 통해 관리된다.

    // 중략
     const setErrorMessage = useSetRecoilState(errorState);
    
       try {
         const res = await instance.get(`/pingpong/notifications`);
         setNotiData(res?.data.notifications);
         setClickRefreshBtn(false);
       } catch (e) {
         setErrorMessage('JB04'); // axios 요청에서 catch가 에러를 잡아준다.
       }
    // 중략
  • 데이터 요청 시 에러가 발생하면 해당 에러코드를 errorMassege에 넣어준다. errorMessage가 바뀌면 Layout 바깥의 errorChecker에서 에러를 감지해 에러페이지를 띄어준다.

    import { errorState } from 'utils/recoil/error';
    import { useRecoilValue } from 'recoil';
    import ErrorPage from 'components/error/Error';
    import styles from 'styles/Layout/Layout.module.scss';
    
    interface ErrorCheckerProps {
     children: React.ReactNode;
    }
    
    export default function ErrorChecker({ children }: ErrorCheckerProps) {
     const errorMessage = useRecoilValue(errorState);
    
     return errorMessage === '' ? (
       <>{children}</> // 에러메시지가 없다면 정상적으로 동작한다.
     ) : (
       <div className={styles.appContainer}>
         <div className={styles.background}>
           <ErrorPage /> //에러메시지가 리코일로 세팅되면 감지하여 에러페이지를 띄어준다.
         </div>
       </div>
     );
    }

    _app.tsx 파일의 구성이다. 메인페이지를 띄우기 전에 에러를 감지하여 페이지를 띄어줄 수 있다.

    // 중략
    return (
     // 중략
         <RecoilRoot>
           <LoginChecker>
             <ErrorChecker>
               <Layout>
                 <Component {...pageProps} />
               </Layout>
               <ModalProvider />
             </ErrorChecker>
           </LoginChecker>
         </RecoilRoot>
    );

2. 잘못된 url 접근

  • 잘못된 url로 접근하면 일반적으로 브라우저에서 404 NotFound를 띄어준다.

  • NextJs에서는 이 경우 에러 페이지로 넘어갈 수 있게 custom error page를 만드는 기능도 존재한다. 이 기능을 이용하여 에러 페이지를 만들어 404페이지를 프로젝트에 맞추어 처리해주었다.

  • pages 폴더에서 404.jsx파일을 만들어주게 되면 페이지를 찾을 수 없을 때 해당 페이지로 이동시켜 준다.

    import { useSetRecoilState } from 'recoil';
    import { useEffect } from 'react';
    import { errorState } from 'utils/recoil/error';
    import ErrorPage from '../components/error/Error';
    
    const Error = () => {
     const setErrorMessage = useSetRecoilState(errorState);
    
     useEffect(() => {
       setErrorMessage('DK404');
     }, []);
      
     return <ErrorPage />;
    };
    • 로그인 시 token을 url에 담아 보내준다. 이를 악용할 수 있기 때문에 로그인할 당시를 제외하고 query에 token을 담아 접근하는 경우 모두 로그아웃 시키고 새로 로그인을 하도록 막아주었다.

3. 매치 관련 기능 동작 문제

  • 현재 구현된 상태는 실시간으로 데이터가 주고 받아지는 상태가 아니기 때문에 새로고침을 하지 않으면 사용자가 보았을 때 과거의 정보로 동작하는 경우가 발생한다.
  • 새로고침 되지 않아 발생하는 문제는 에러페이지가 아닌 서버로부터 상태코드를 받아 alert창을 띄워주고 새로고침을 해주는 방식으로 구현해주었다.
       try {
         const body = { slotId };
         await instance.post(`/pingpong/match/tables/${1}/${type}`, body);
         alert('경기가 성공적으로 등록되었습니다.');
       } catch (e: any) {
         if (e.response.data.code === 'SC001')
           alert('경기 등록에 실패하였습니다.');
         else if (e.response.data.code === 'SC002')
           alert('이미 등록이 완료된 경기입니다.');
         else if (e.response.data.code === 'SC003')
           alert('경기 취소 후 1분 동안 경기를 예약할 수 없습니다.');
         else {
           setErrorMessage('JH05');
           return;
         }
       }
       window.location.reload();
  • e.resopnse.data.code를 확인하는 부분이 경기 등록에 문제가 발생한 경우이다. 이 경우 code로 어떤 상황인지 파악하여 그 상황에 맞는 설명을 사용자에게 띄어주고 reload를 통해 페이지를 새로고침 시켜준다. 취소도 같은 형태로 구현해주었다.

4. 참고

https://velog.io/@carrot/Next.js-%EC%97%90%EB%9F%AC-%ED%8E%98%EC%9D%B4%EC%A7%80-%EB%A7%8C%EB%93%A4%EA%B8%B0


※ 에러 코드 정리

1개의 댓글

comment-user-thumbnail
2022년 8월 7일

이번에 시퀀스 다이어그램을 배우면서 Recoil에 대한 용어를 처음 접하게 되었는데, 이 글을 통해 Recoil이 어떻게 사용되는건지 조금 더 이해할 수 있었습니다. 그리고 궁금한 점이 기본으로 제공해주는 alert함수가 어떻게 멋진 메시지 창으로 보여지는지 신기합니다. css를 통해 이미 수정된 메시지 창이 저희에게 보여진 것인지, 아니면 alert함수를 직접 구현하신건지 궁금합니다

답글 달기