[리액트] 에러 바운더리 (에러 경계)

임승민·2022년 11월 3일
0

React

목록 보기
14/14
post-thumbnail

에러 바운더리 왜 사용할까?

만약 JS 에러가 발생해 React의 내부 상태를 훼손하는 경우가 발생할 수 있다.

손상된 UI가 사용자에게 보여진다면 화면을 보여주지 않는 것 보다 더큰 문제가 된다.

예를 들어 결제 페이지에 문제가 생겨서 금액이나 예금자가 잘못 보여진다면 화면이 나오지 않는 것이 더 좋은 방안일 수 있다.

그렇다고 모든 컴포넌트의 로직을 try-catch로 감싸긴 힘들다. 그래서 리액트에선 에러 바운더리라는 컴포넌트를 만들었고 에러 바운더리 하위 컴포넌트 트리에서 JS 에러가 감지되면 잘못 된 화면대신 설정해 둔 폴백 UI를 보여준다.

하지만 에러 바운더리가 모든 에러를 감지하는 것은 아니다. 리액트 공식 문서에선 아래의 에러의 경우 포착하지 않는 다고 설명한다.

에러 경계는 다음과 같은 에러는 포착하지 않습니다
-
이벤트 핸들러 (더 알아보기)

  • 비동기적 코드 (예: setTimeout 혹은 requestAnimationFrame 콜백)
  • 서버 사이드 렌더링
  • 자식에서가 아닌 에러 경계 자체에서 발생하는 에러

따라서 하위 컴포넌트, 렌더링 중 발생하는 라이프 사이클 메서드에서 발생하는 에러만 처리해주기 때문에 위의 경우에는 따로 에러처리를 따로 해줘야 한다.


에러 바운더리 사용하기

사용예제는 리액트 공식문서에 있다.

나는 TS로 작업을 해서 레퍼런스를 찾다가 React TypeScript Cheatsheet라는 사이트에서 TS로 마이그레이션 된 컴포넌트가 있어 참고했다. 아! 그리고 ts확장자를 했다가 안되서 찾아보니 tsx확장자를 이용하니 잘 동작하였다. react-dom을 반환할 때는 tsx확장자를 이용하라고 한다.

참고로 ts, tsx차이는 아래와 같다.

.ts 파일에는 순수 TypeScript만 포함된다.
.tsx에는 JSX도 포함되어 있다.

공식문서 사용예제

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

  static getDerivedStateFromError(error) {
    // 다음 렌더링에서 폴백 UI가 보이도록 상태를 업데이트 합니다.
    return { hasError: true };
  }

  componentDidCatch(error, errorInfo) {
    // 에러 리포팅 서비스에 에러를 기록할 수도 있습니다.
    logErrorToMyService(error, errorInfo);
  }

  render() {
    if (this.state.hasError) {
      // 폴백 UI를 커스텀하여 렌더링할 수 있습니다.
      return <h1>Something went wrong.</h1>;
    }

    return this.props.children;
  }
}

함수형은 없고 클래스 컴포넌트 밖에 없으니 참고하면 될 것 같다.

여기서 크게 수정할 부분은 h1태그가 있는 곳에 원하는 커스텀 폴백UI를 넣어주면 된다.

static getDerivedStateFromError()와 componentDidCatch() 중 하나 혹은 둘다 정의하면 클래스 컴포넌트 자체가 에러 바운더리 된다.

static getDerivedStateFromError(): 에러 발생 후 폴백 UI를 렌더링 하려면 이 메소드 사용

componentDidCatch(): 에러 정보를 기록하려면 이 메소드 사용

테스트를 위해서 throw new Error('forced error') 를 통해 임의로 에러를 발생시키니 잘 동작한다.


폴백UI에서 페이지 이동


위: link, useNavigate 이용
아래: a태그 이용

폴백UI에서 메인페이지로 이동하는 버튼을 만들었는데 link태그나 useNavigate를 사용하니 경로만 바뀌고 새로고침이 이루어지지 않아 a태그를 이용해 구현하였다.

<button onClick={navigate('/');}>메인으로 이동</button> //X
<link href="/">메인으로 이동</link> //X
<a href="/">메인으로 이동</a> //O

0개의 댓글