"일꾼이 일을 잘하려면 먼저 도구를 갈고 닦아야 한다." - 공자, 『논어』.
첫 장 > 프로그램 작성 > GlobalErrorHandler: ErrorBoundary의 손가락 사이로 떨어지는 오류를 잡아보세요!

GlobalErrorHandler: ErrorBoundary의 손가락 사이로 떨어지는 오류를 잡아보세요!

2024-11-07에 게시됨
검색:237

GlobalErrorHandler: Catch the errors that falls through ErrorBoundary

ErrorBoundary는 React 구성 요소에서 발생한 오류를 캡처하는 훌륭한 도구입니다. 오류 자체의 성격과 위치에 따라 사용자 정의 오류 메시지를 제공할 수 있습니다. 그러나 발생하는 모든 오류가 ErrorBoundary에 의해 처리되는 것은 아닙니다! 그걸로 무엇을 하시나요?

비동기 오류와 React 외부에서 발생하는 오류를 모두 고려할 때 ErrorBoundary는 부족합니다. 이 문제를 완화하기 위해 저는 애플리케이션에서 GlobalErrorHandler라고 부르는 것을 만들었습니다. 단순히 A) 오류 대화 상자를 표시하여 사용자에게 무언가가 잘못되었음을 알리고, B) 오류를 서버에 기록하여 해결 방법을 조사하고 찾을 수 있도록 하는 기능 구성 요소입니다.

아이디어는 간단합니다. 우리는 애플리케이션의 루트에 하나의 GlobalErrorHandler를 원합니다. 이 핸들러는 ErrorBoundary에 의해 포착되지 않은 오류만 처리해야 합니다. 게다가 사용자가 쉽게 닫을 수 있어야 하며 애플리케이션을 계속 사용할 수 있다고 가정해야 합니다.

따라서 전략은 다음과 같습니다. GlobalErrorHandler는 기본적으로 하위 항목을 렌더링하는 것 외에는 아무 작업도 수행하지 않습니다. 그러나 브라우저에서 모든 오류 및 처리되지 않은 거부 이벤트를 수신하는 두 개의 이벤트 리스너를 설정합니다. 그런 다음 오류를 검사하고 이미 ErrorBoundaries에 의해 처리되었는지 확인합니다. 마지막으로 그렇지 않은 경우 대화 상자를 표시하여 사용자에게 어딘가 잘못되었음을 알리고 사용자가 대화 상자를 닫고 애플리케이션을 계속 사용할 수 있도록 합니다.

오류가 이미 처리되었나요?

ErrorBoundary가 수행한 처리 외에 불필요한 대화 상자로 최종 사용자를 괴롭히기 전에 먼저 오류를 묻는 것부터 시작해야 합니다. 이미 처리되었습니까? 이에 대한 나의 해결책은 오류 개체 isHandledByBoundary에 새 필드를 도입하는 것입니다. 이는 ErrorBoundary:
내에서 true로 설정됩니다.

  componentDidCatch(error: Error, errorInfo: ErrorInfo) {
    (error as any).isHandledByBoundary = true;
    ....
  }

모든 ErrorBoundary 구성 요소(및 포착되지 않은 오류를 처리하는 기타 기계)에 이 기능이 적용되었으므로 GlobalErrorHandler 정의를 시작할 준비가 되었습니다.

벌거벗은 해골

그런 다음 GlobalErrorHandler의 뼈대를 구축할 수 있습니다. 자식을 간단하게 렌더링하고 다른 곳에 정의된 "ErrorDialog"도 렌더링합니다. (이 구성 요소를 여러 응용 프로그램에서 공유하려면 ErrorDialog가 대신 소품이 될 수 있습니다.)

import { useState, useEffect, ReactNode } from 'react';
import { ErrorDialog } from '../Components/ErrorDialog';

type Props = {
  children: ReactNode;
};

export function GlobalErrorHandler({ children }: Props) {
  const [error, setError] = useState(null);
  const [isDialogOpen, setDialogOpen] = useState(false);

  useEffect(() => {
    ....
  }, []);

  function handleCloseDialog() {
    setDialogOpen(false);
    setError(null);
  }

  return (
    
      {children}

      {isDialogOpen && error && (
        
      )}
    >
  );
}

현재 부족한 유일한 것은 useEffect 내에 정의된 오류 처리 자체입니다.

오류 처리

이 섹션의 모든 코드는 useEffect 함수 내에 위치해야 합니다!

먼저 handlerWindowError를 정의합니다. 이는 창 개체의 오류 이벤트 처리기로 전달됩니다. 여기에는 신비한 것이 없지만 오류 이벤트에는 소스, 줄 번호 및 열 번호에 대한 정보도 포함되어 있습니다. 수집하기에 가치가 있을 수 있습니다.

보통 이 정보는 오류 개체 내에서도 찾을 수 있지만 이에 대해 좀 더 실증적인 조사가 필요합니다. 아마도 오류 이벤트에 의해 보고된 대로 줄과 열 번호를 항상 유지해야 할까요? 이 경우 GlobalErrorHandler 내에서 이에 대한 상태를 가질 수도 있습니다(오류를 기록할 때 이 상태가 전송되는지 확인하세요).

   function handleWindowError(
      message: string | Event,
      source?: string,
      lineno?: number,
      colno?: number,
      error?: Error
    ) {
      if (error && (error as any).isHandledByBoundary) {
        return true;
      }

      const errorMessage = error
        ? error
        : `Error: ${message} at ${source}:${lineno}:${colno}`;
      setError(errorMessage);
      setDialogOpen(true);
      return true;
    }

handleUnhandledRejection 핸들러도 정의합니다. 이는 Promise 내에서 발생하는 오류에 대한 것이지만 .catch() 절을 작성하는 것을 잊어버렸습니다.

    function handleUnhandledRejection(event: PromiseRejectionEvent) {
      setError(`Unhandled promise rejection: ${event.reason}`);
      setDialogOpen(true);
    }

그런 다음 우리가 해야 할 일은 리스너를 설정하고 GlobalErrorHandler가 더 이상 렌더링되지 않을 때마다 리스너를 제거하는 것입니다.

    window.addEventListener('error', handleWindowError);
    window.addEventListener('unhandledrejection', handleUnhandledRejection);

    return () => {
      window.removeEventListener('error', handleWindowError);
      window.removeEventListener(
        'unhandledrejection',
        handleUnhandledRejection
      );
    };

물론 return 문은 useEffect를 제공하는 함수에서 반환되는 곳입니다. 이렇게 하면 이벤트 수신을 시작하고 구성 요소가 렌더링될 때 이벤트를 처리하고 구성 요소가 더 이상 렌더링되지 않을 때 중지됩니다.

따라서 비동기 소스에서 발생하거나 React 구성 요소 외부에서 발생하는 React 애플리케이션의 성가신 오류를 처리하기 위한 GlobalEventHandler가 있습니다!

릴리스 선언문 이 기사는 https://dev.to/lebbe/globalerrorhandler-catch-the-errors-that-falls-through-errorboundarys-fingers-3m5d?1에서 복제됩니다. 침해가 있는 경우, [email protected]으로 문의하시기 바랍니다. 그것을 삭제하려면
최신 튜토리얼 더>

부인 성명: 제공된 모든 리소스는 부분적으로 인터넷에서 가져온 것입니다. 귀하의 저작권이나 기타 권리 및 이익이 침해된 경우 자세한 이유를 설명하고 저작권 또는 권리 및 이익에 대한 증거를 제공한 후 이메일([email protected])로 보내주십시오. 최대한 빨리 처리해 드리겠습니다.

Copyright© 2022 湘ICP备2022001581号-3