리액트 에러 관리 (ErrorBoundary, react-error-boundary)

fethpiao·2023년 8월 6일
5
post-custom-banner

문제 상황

리액트에서 ui 렌더링 중 에러 발생 시, 흰 화면이 노출되며 리액트 애플리케이션이 중지되게 됩니다. 서버 데이터 필드에 잘못 접근한 경우, 네트워크 혹은 프론트 로직에 인한 오류, 그리고 각종 에러 등에 대해서 일일히 핸들링 하기란 불가능에 가깝습니다.

또한 에러는 날 수 있다 하더라도, 조그만 에러가 애플리케이션 전체를 중단시켜서 화면 전환조차 불가한 불상사는 막아야 할 것입니다. 이러한 에러 핸들링에 가장 편리하고, ui 상으로도 이상적인 방안으로 React16의 ErrorBoundary가 있습니다.

ErrorBoundary

ErrorBoudary - React 공식 홈페이지

에러 경계는 하위 컴포넌트 트리의 어디에서든 자바스크립트 에러를 기록하며 깨진 컴포넌트 트리 대신 폴백 UI를 보여주는 React 컴포넌트입니다. 에러 경계는 렌더링 도중 생명주기 메서드 및 그 아래에 있는 전체 트리에서 에러를 잡아냅니다. (by 리액트 공식 싸이트)

정리하자면

<ErrorBoundary>
	<Compoents />
</ErrorBoundary>

의 형태로 에러 바운더리 하위에서 발생한 에러를 캐치하고, 에러 발생 시에는 보여줄 화면을 미리 지정해 둘 수 있다는 것입니다.

React16의 ErrorBoundary의 아쉬운점 (개인적)

에러바운더리는 리액트스럽게 선언적이고 미리 에러 페이지를 설정할 수 있는 등 매우 훌륭합니다만, 개인적으로 단 한가지 아쉬운 점이 있습니다.

바로 공식홈페이지의 안내는 클래스형이라는것..! 입니다.

class ErrorBoundary extends React.Component {
  constructor(props) {
    super(props);
    this.state = { hasError: false };
  }

  componentDidCatch(error, errorInfo) {
    do something...
  }

  render() {
    if (this.state.hasError) {
      return <h1>에러 페이지</h1>;
    }

    return this.props.children;
  }
}

클래스형으로 작성된 ErrorBoundary는 사용하시는 리액트 프로젝트가 대부분의 경우처럼 함수형으로 작성되었을 경우 일관성을 해치게 됩니다. 리액트를 함수형으로 처음 접한 분들에게는 더욱 낯설고, 클래스형의 복잡한 생명주기에 대해 이해가 부족하여 개발에 어려움이 있을 수도 있겠습니다.

react-error-boundary

react-error-boundary npm 페이지

react-error-boundary는 현재일(23.08월)기준 Weekly Downloads 330만에 달하는 라이브러리 입니다. 공식 홈페이지에서 안내된 클래스형 errorBoundary와 거의 동일한 기능을 사용하면서도, 최근 리액트 개발의 주류인 함수형으로 errorBoundary를 작성할 수 있습니다.

그외 장점

함수형으로 작성된 errorBoundary라는 것 외에도 장점이 있습니다.

  • 재사용성이 좋음
    에러시의 fallback렌더값을 props로 받고 있습니다. 클래스형에서 같은 작업을 해야했다면 별도로 재사용성을 높이기 위한 커스텀을 해줘야했거나 여러개의 에러 바운더리를 생성해야 했겠지만, 프롭스만으로 다르게 처리할 수 있게 되어 있습니다.
    이를통해 프로젝트 내의 여러 부분의 특성에 맞게 에러 컴포넌트를 처리하거나, 페이지 단위보다 작은 파트를 단위로 에러 컴포넌트를 보여주는데 유용하게 처리할 수 있겠습니다.

기본 props소개

react-error-boundary의 기본 props로는 에러 발생 시 보여줄 컴포넌트인 fallback, fallbackRender 등이 있습니다.

사용예)

<ErrorBoundary
      fallbackRender={fallbackProps => <ErrorFallback {...fallbackProps} />}
    >
    {children}
    </ErrorBoundary>
  • fallbackRender
    에러시 보여줄 컴포넌트. 해당 prop은 발생한 에러에 대한 정보인 error 와, 에러바운더리를 리셋하고 렌더링을 다시 시도하는 함수는 resetErrorBoundary 함수를 파라미터로 넘겨줍니다.
    이를 활용해서 fallbackRender에 넘겨준 컴포넌트 안에서 error 타입별로 다른 에러를 보여주거나, 로깅을 하는데 사용할 수 있겠습니다. 또한 resetErrorBoundary을 받은 후 화면에서 '다시 시도하기' 등의 버튼을 넣어줌으로써 ux를 개선할 수도 있습니다.
const ErrorFallback = ({ error, resetErrorBoundary }: FallbackProps) => {

return (
      <section>
        <div>
          <p>이용에 불편을 드려 죄송합니다.</p>
          <p>
            동일한 현상이 계속될 경우 문의 주시기 바랍니다.
          </p>
          <button onClick={resetErrorBoundary}>
            다시 시도하기
          </button>
        </div>
      </section>
      )
}
  • resetKeys
    react-error-boundary에서 수상하리만큼 설명이 없는 속성입니다. 에러바운더리에 key를 지정하므로써 key가 바뀌면 자동으로 리셋을 하게 됩니다.
    한 화면에서 에러가 났지만, 메뉴 이동을 했을때는 사용자 입장에서 다른 페이지이므로 에러를 리셋해주고 싶을 때 유용하게 사용할 수 있습니다.
<ErrorBoundary resetKeys={location.pathname}> {cildren} </ErrorBoundary>
  • onReset
    에러 바운더리가 리셋될 때 호출되는 속성. 에러 폴백 내에서 resetErrorBoundary를 호출할때 등 실행됩니다.

React-query와의 조합

대표적인 서버상태관리 라이브러리인 react-query를 사용하는 경우, errorBoundary에서 에러 발생 후 reset 시 쿼리를 재시도하게 할 수 있습니다. 이 때 react-query의 useQueryErrorResetBoundary 훅을 사용하면, react-query의 QueryErrorResetBoundary 하위에 있는 쿼리 오류를 재설정 합니다. (미설정 시 전역으로 재설정)

const ErrorHandler = () => {

const { reset } = useQueryErrorResetBoundary()

return (
 	<ErrorBoundary onReset={reset}>
    	{children} 
    </ErrorBoundary>
    )
}

주의) react-query의 설정에 useErrorBoundary: true 속성을 세팅해줘야 오류 발생 시 errorBoundary에서 감지할 수 있다고 함.

 new QueryClient({
   queries: {
      useErrorBoundary: true
    }
 })
profile
웹프로그래머
post-custom-banner

0개의 댓글