개인공부/react

에러 바운더리 (Error Boundaries)

minseokiim 2024. 12. 11. 17:01

 
* 간단하게 적는 도입 이유
: 가장 상단에서 페이지에 진입하게 되면, api를 여러 개 호출하는데
한가지의 api 관련 에러 때문에 페이지 전체가 보이지 않는 에러가 생겼다.

이 api는 하나의 작은 버튼만을 표출하는 역할을 하는데,
이 오류 하나로 페이지가 표출되지 않는다면 너무 큰 문제기 때문에 에러 바운더리를 도입하게 되었다.

 

🗂️ 에러 바운더리 (Error Boundaries)

UI의 일부분에 존재하는 자바스크립트 에러가 전체 애플리케이션을 중단시켜서는 안 된다.
→ 그래서 등장한 것이 에러 바운더리
 
React 16부터는 에러 경계에서 포착되지 않은 에러로 인해 전체 React 컴포넌트 트리의 마운트가 해제 됨.
손상된 UI를 완전히 제거하는 것보다 그대로 남겨두는 것이 더 좋기 때문
 
전체 컴포넌트 트리의 마운트를 해제하는 대신, 깨진 UI를 교체하는 방식으로 오류를 처리하여 애플리케이션의 일부 UI가 여전히 사용자에게 표시될 수 있도록 함.
 

- 역할

React 컴포넌트 트리 내에서 발생하는 JavaScript 오류를 포착하고, 오류가 발생한 부분을 완전히 제거하는 대신 fallback UI를 렌더링하여 애플리케이션이 멈추지 않게 함.
에러 바운더리 하위 컴포넌트 트리의 자바스크립트 에러를 기록
 

- 작동 방식

렌더링 도중 발생한 에러 생명주기 메서드에서 발생한 오류를 잡을 수 있음.
getDerivedStateFromError()와 componentDidCatch() 메서드를 사용하여 오류 발생 후 폴백 UI를 렌더링하거나, 오류 로그를 기록
 

- 에러 바운더리가 잡지 않는 오류

1. 이벤트 핸들러에서 발생하는 오류
이유 : 이벤트 핸들러는 렌더링 중에 발생하지 않기 때문에, 이벤트 핸들러가 에러를 던져도 React는 여전히 화면에 무엇을 표시해야 할지 알고 있음.
ex. 버튼 클릭시 발생하는 오류
-> 이러한 오류를 처리하려면? 이벤트 핸들러 내에서 발생한 에러는 일반 자바스크립트의 try/catch 구문을 사용
 
2. 비동기 코드에서 발생하는 오류
이유 : 비동기 작업이 렌더링 주기 외부에서 발생하기 때문
ex. setTimeout이나 API 호출 등 비동기 작업에서 발생하는 오류
-> 이러한 오류를 처리하려면? useSuspenseQuery를 사용 + try/catch 구문을 비동기 코드에 적용
 
3. 서버 사이드 렌더링(SSR)
이유 : 클라이언트 사이드에서와 같은 방식으로 에러 바운더리가 작동하지 않음.
React가 서버에서 HTML을 렌더링할 때는 클라이언트의 라이프 사이클과 다르게 동작하기 때문.
ex. SSR 환경에서 API 호출 중 오류 발생
-> 이러한 오류를 처리하려면? SSR에서는 별도의 에러 처리 로직이나 서버 측 오류 경계를 구현
 
4. 자식 컴포넌트가 아닌 에러 바운더리 자체에서 발생하는 오류
이유 : React는 상위 컴포넌트에서 발생한 오류만 처리할 수 있기 때문
에러 바운더리 내에서 발생하는 오류는 자체적으로 처리되지 않음.
-> 이러한 오류를 처리하려면? 예방하기 위한 로직을 별도로 추가
 

- 에러 바운더리 사용법

클래스 컴포넌트에서 에러 바운더리를 사용
-> 생명주기 메서드인 static getDerivedStateFromError()와 componentDidCatch()를 정의하기

  • 에러 발생 후 폴백 UI를 렌더링 :  getDerivedStateFromError()
  • 에러 정보를 기록 : componentDidCatch()

 

- 리액트 공식 문서에 나온 예시

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;
  }
}

 
작성하고, 부모에서 적용
 

<ErrorBoundary>
  <MyWidget />
</ErrorBoundary>

 
해주면, <MyWidget />의 내부에서 발생한 에러는 잡힘.
 
 
* 참고
https://ko.legacy.reactjs.org/docs/error-boundaries.html

에러 경계(Error Boundaries) – React

A JavaScript library for building user interfaces

ko.legacy.reactjs.org

 
 

- 함수형 컴포넌트에서 에러 바운더리 사용법

react-error-boundary 라이브러리를 활용
 
* 참고 
https://www.npmjs.com/package/react-error-boundary

react-error-boundary

Simple reusable React error boundary component. Latest version: 4.1.2, last published: 2 months ago. Start using react-error-boundary in your project by running `npm i react-error-boundary`. There are 1400 other projects in the npm registry using react-err

www.npmjs.com