Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[FE] 에러 발생 시 에러 처리 시스템을 트리거하지 않고 무시할 수 있는 기능 추가 #973

Merged
merged 9 commits into from
Feb 5, 2025

Conversation

pakxe
Copy link
Contributor

@pakxe pakxe commented Jan 22, 2025

issue

구현 목적

지금은 에러 발생 시 'toast' 또는 'errorBoundary'로만 처리합니다.

페이지나 컴포넌트 내부에서 독자적인 에러 핸들링 방법을 사용하거나, 부차적인 api라 에러 핸들링이 필요하지 않을 경우 무시할 수 있는 옵션인 ignore를 추가합니다.

구현 사항

RequestGetError의 errorHandlingStrategy에 'ignore'를 추가했습니다.
api의 호출 상황(위치)에 따라 errorHandlingStrategy를 조작할 필요가 있는 경우 request함수를 아래처럼 작성하고 errorHandlingStrategy를 주입합니다.

// 정의
export const requestGetUserInfo = async ({...props}: WithErrorHandlingStrategy | null = {}) => { // 에러 핸들링 전략을 받을 수도 있음을 의미
  return await requestGet<UserInfo>({
    baseUrl: BASE_URL.HD,
    endpoint: `${USER_API_PREFIX}/mine`,
    ...props, // 에러 핸들링 전략을 넘겨주기
  });
};

// 사용
requestGetUserInfo({errorHandlingStrategy: 'ignore'}) //  'toast' | 'errorBoundary' | 'ignore'

전역 에러 핸들링 시스템을 사용하지 않고 독자적으로 커스텀한 에러 핸들링을 사용하고 싶을 때 또는 그냥 무시하고 싶을 때 'ignore'옵션을 사용합니다.

사용 모습

[▼ ignore]

ignore.mov

[▼ 독자적인 에러 핸들링을 사용하고 싶을 때]

ignore.+.example.mov

🚨 유의사항

  • useQuery + 'ignore'를 사용할 경우 useQuery에서 throwOnError: false옵션과 함께 사용합니다. 옵션을 주지 않으면 ignore가 안됩니다. 그 외 옵션('toast' | 'errorBoundary')은 별다른 조치 없이 errorHandlingStrategy값만 주면 동작합니다.
  • useSuspenseQuery + 'ignore'는 사용할 수 없습니다. api호출 시 에러 발생했다면 무조건 컴포넌트에서 에러를 던지는 쿼리이기 때문에.. ignore불가능. 그리고 만약 그게 가능하다고 하더라도, useSuspenseQuery는 유효한 데이터를 보장하도록 하는데 ignore가 가능하게 된다면 이에 반하는 행위가 됨.
  • useSuspenseQuery + ('ignore' | 'errorBoundary') + initialData는 initialData가 있기 때문에 throw error를 하지 않습니다. 그래서 ignore된 것 처럼 동작합니다.

@pakxe pakxe added 🖥️ FE Frontend ⚙️ feat feature labels Jan 22, 2025
@pakxe pakxe added this to the v3.2.0 milestone Jan 22, 2025
@pakxe pakxe self-assigned this Jan 22, 2025
Copy link

Copy link

Copy link
Contributor

@jinhokim98 jinhokim98 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

고생했습니다 웨디~ 이 기능이 필요한 이유가 랜딩 페이지에서 내 정보를 불러오지 못 할 경우 UnpredictableErrorBoundary가 보이지 않게 하기 위해서 인가요?

그리고 ignore가 throwOnError가 켜지지 않아서 에러 바운더리가 보이지 않고 catch로 특정 에러처리를 보여준다는 의미인거죠?

QueryClientBoundary의 throwOnError 설정을 ignore일 때는 false가 되게 할 수 있지 않을까 생각해봤지만 쉽지 않을 것 같아서... ignore를 사용할 때 throwOnError를 false로 해줘야 한다고 팀원들이 인지할 수 있다면 괜찮을 것 같아요

@@ -1,4 +1,5 @@
import {MutationCache, QueryCache, QueryClient, QueryClientProvider} from '@tanstack/react-query';
import {useEffect} from 'react';
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

요 문장 지워도 될 것 같아요!

Copy link
Contributor Author

@pakxe pakxe Jan 23, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

오 좋아용!

approve 코멘트에는 답글을 달 수 없어서..

이 기능이 필요한 이유가 랜딩 페이지에서 내 정보를 불러오지 못 할 경우 UnpredictableErrorBoundary가 보이지 않게 하기 위해서 인가요?
여기서는 useSuspenseQuery가 사용되기 때문에 ignore를 함께 사용할 수 없습니다. 현재 ignore로 strategy를 세팅해놓은 이유는 무시된다를 명시적으로 표현하기 위해 써놓은 것이에요. 그리고 default값이 'toast'라서 인자를 안넘기면 토스트가 뜨기도 하구요.

이 전역 에러 핸들링 시스템은 속도감 있는 개발을 위해 페이지 안에서 핸들링 코드를 매번 작성하지 않아도 되도록(에러 자체에 신경쓰지 않을 수 있도록)하는 게 가장 큰 개발 목적이었습니다. 실제로 페이지 안에 에러 핸들링 코드 없이 빠르게 개발할 수 있었어요.

한창 프로젝트를 개발해나갈 때는 자체적인 에러 핸들링이 필요하지 않았죠. 그런데 얼마 전에 소하 pr이었던 것 같은데 쿠키가 "왜 여기서 자체적으로 에러 핸들링을 하고있나요? 전역 에러 핸들링 시스템에 기대지않고?" 라고 했던게 생각났어요. (지금은 어떻게 되었는지 모르겠으나 ㅠ) 그래서 어떤 곳에서 사용되느냐에 따라 자체적인 에러 핸들링이 필요한 상황이 곧 올 수 있을 거라 생각되었어요. 예를 들어 에러 코드에 매칭되는 에러 메세지가 아니라 그냥 이 api에서 오류가 났을 경우 뭐.. "잠시후 다시 시도해주세요" 토스트만으로 통일할 수도 있구요. 이 ignore가 자주 사용되어야 한다 라는 목적으로 만든 것은 아니고, TopNav를 수정하기 전에는 left, right 좌우로 나눠 보여주기 위해 다양한 하드코딩이 있었죠. 비슷한 일이 일어나지 않도록 사전에 방지하기 위한 변경이라고 생각해주시면 될 것 같아요.

그리고 ignore가 throwOnError가 켜지지 않아서 에러 바운더리가 보이지 않고 catch로 특정 에러처리를 보여준다는 의미인거죠?

네, 에러 바운더리를 트리거하지 않은 채로 자체적으로 핸들링을 하고 싶다면 catch안에 로직을 작성해주면 됩니다.

QueryClientBoundary의 throwOnError 설정을 ignore일 때는 false가 되게 할 수 있지 않을까 생각해봤지만 쉽지 않을 것 같아서... ignore를 사용할 때 throwOnError를 false로 해줘야 한다고 팀원들이 인지할 수 있다면 괜찮을 것 같아요

혹시나 이유를 알고 계실까봐 물어보는건데요..! queryClientBoundary안에서 얼리리턴을 할 경우는 throwOnError옵션을 false로 해야만 ignore가 동작합니다. 그러나 얼리리턴하지않고 updateError를 하도록 냅두고 ErrorCatcher의 useEffect안에서 얼리리턴할 경우는 throwOnError옵션을 안켜도 동작하긴 하더라구요. 다만 이렇게 동작하는 이유를 찾지 못했고.., 어떤건 queryClientBoundary에서 return하고 어떤건 ErrorCatcher에서 return하는게 직관적이지도 않고 유지보수를 어렵게 만들 것이라 생각되었어요.

그래서 지금은 불편하지만 throwOnError를 함께 사용하도록 하고 얼리리턴은 모두 queryClientBoundary에서만 수행하고 있는데요. 이유가 무엇일지 예측이 되시나요?! ㅠㅠ

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

오~ 자세한 설명 감사해요!

맞아요! try catch 문을 보고 제가 소하에게 질문했었습니다~ try catch를 사용한 이유는 서버에서 내려주는 에러 메시지를 사용자가 봤을 때 어색하기 때문이었다고 들었습니다. 저도 ignore는 최소한으로 사용해야 한다고 생각합니다. ignore를 자주 사용하게 되면 서버에서 내려주는 에러 메시지가 무의미 해지니깐요!

제가 어렵다고 생각한 것은 throwOnError 설정의 위치 때문이었어요. 이게 defaultOptions에 설정돼있어서 기본 값이 true이고 에러 처리 전략을 넣어주는 설정은 request~~에서 설정해서 defaultOptions에서 분기처리 할 수가 없다고 생각했어요,,ㅠ

흠 근데 왜 throwOnError가 true일 때는 왜 ignore이 작동하지 않는지는 잘 모르겠네요😥😥

  defaultOptions: {
      queries: {
        throwOnError: true,
        ...
      },
    },
  queryCache: new QueryCache({
      onError: (error: Error) => {
        if (error instanceof RequestGetError && error.errorHandlingStrategy === 'errorBoundary') return;
        if (error instanceof RequestGetError && error.errorHandlingStrategy === 'ignore') return;

        updateAppError(error);
      },
    }),

errorHandlingStrategy는 여기서 설정....

export const requestGetKakaoLogin = async (code: string) => {
  await requestGetWithoutResponse({
    baseUrl: BASE_URL.HD,
    endpoint: `/api/login/kakao?code=${code}&redirect_uri=${getKakaoRedirectUrl()}`,
    errorHandlingStrategy: 'errorBoundary',
  });

  return null;
};

Copy link

Copy link
Contributor

@Todari Todari left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

에러처리의 신... 딱히 댓글을 달 것 도 없네요 ㅜㅜㅜ
고생 많았슴당 웨디~!

Copy link
Contributor

@soi-ha soi-ha left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

오-! 구현해주신 부분을 보고 저도 제가 저번에 올렸던 pr 내용이 떠올랐었는데! 이렇게 멋있게 구현해주셨군요! 감사합니다!!

적용할 수 있는 부분에는 한번 적용해볼게요!

@Todari Todari merged commit 716793c into fe-dev Feb 5, 2025
2 checks passed
@Todari Todari deleted the feature/#965 branch February 5, 2025 06:26
@Todari Todari mentioned this pull request Feb 5, 2025
jinhokim98 pushed a commit that referenced this pull request Feb 5, 2025
* fix: iOS에서 아이콘이 제대로 보이지 않던 문제 (#948)

* fix: Icon component의 viewBox px 단위로 변경

* fix: Icon Component가 제대로 보이지 않던 문제 해결

* feat: 에러 처리 시스템에서 처리하지 않도록하는 ignore 옵션 추가

* feat: ignore옵션일 경우 에러 무시하도록 함

* feat: getUserInfo api호출 시 errorHandlingStrategy를 받을 수 있도록 함

* feat: useRequestGetUserInfo에서 enableInitialDate가 true인 경우 ignore옵션을 사용하도록 함

* chore: 불필요한 라인 제거

* feat: ignore를 기능하게 하는 라인 위치 수정

* chore: 사용하지 않는 import 제거

---------

Co-authored-by: TaehunLee <[email protected]>
pakxe added a commit that referenced this pull request Feb 5, 2025
* fix: iOS에서 아이콘이 제대로 보이지 않던 문제 (#948)

* fix: Icon component의 viewBox px 단위로 변경

* fix: Icon Component가 제대로 보이지 않던 문제 해결

* feat: 에러 처리 시스템에서 처리하지 않도록하는 ignore 옵션 추가

* feat: ignore옵션일 경우 에러 무시하도록 함

* feat: getUserInfo api호출 시 errorHandlingStrategy를 받을 수 있도록 함

* feat: useRequestGetUserInfo에서 enableInitialDate가 true인 경우 ignore옵션을 사용하도록 함

* chore: 불필요한 라인 제거

* feat: ignore를 기능하게 하는 라인 위치 수정

* chore: 사용하지 않는 import 제거

---------

Co-authored-by: TaehunLee <[email protected]>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
Status: ✅ Done
Development

Successfully merging this pull request may close these issues.

4 participants