react에서 제공하는 ErrorBoundary가 존재한다

ErrorBoundary

생명주기 메서드 중 getDerivedStateFromError와 ComponentDidCatch를 정의하면 ErrorBoundary로 사용할 수 있다. 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의 한계

Screenshot 2024-02-10 at 8.01.11 PM.png

위와 같은 사항을 포착하지 못한다.

해결 방법

그렇다. 위 ErrorBoundary의 한계에서 2번에 해당하는 내용이다. 비동기적 코드는 react-query, swr등의 비동기 통신 라이브러리를 사용해야 한다. 혹은, 직접 에러를 컴포넌트에서 동기적으로 던져주는 방법도 있다.

에러를 throw하는 방법을 공부해보기 위해, 직접 동기적으로 에러를 throw하는 로직을 작성해보자.

1. error를 동기적으로 직접 throw하자

function Children() {
  const [todos, setTodos] = useState([]);
  const [error, setError] = useState(null);

  useEffect(() => {
    (async () => {
      try {
        const res = await axios.get(
          "<https://jsonplaceholder.typicode.com/todos21231>"
        );
        setTodos(res.data);
      } catch (e) {
        setError(e);
      }
    })();
  }, []);

  if (error) {
    throw error;
  }

  return click;
}

데이터를 fetch하는 곳에서 throw를 하는 것이 아니라, 바깥에서 에러를 던지는 것이다. 데이터 fetch하는 함수는 비동기적으로 실행되기 때문에, ErrorBoundary의 try-catch문 바깥에 있어서 포착하지 못한다. 동기적으로 실행되는 곳에서 throw를 해주면 이 throw문은 ErrorBoundary에서 포착하여 에러 화면을 보여줄 수 있다.

2. useError로 error를 throw하는 로직을 추상화하자

그리고, 이러한 error에대한 로직을 커스텀 훅으로 만들었다.