[React] Error Boundaries

13727 ワード

従来、応答では、コンポーネント内部にエラーが発生した場合、これらのエラーを処理する方法は提供されず、アプリケーション全体を中断しました.
そこで,一つの場所で発生したエラーによる全体的な割り込みの問題を解決するために,Error Boundaryが出現した.
Error Boundaryは、サブエレメントツリー内の任意の場所で発生したエラーをキャプチャするためのライフサイクル法を提供する.

getDerivedStateFromErrorライフサイクルメソッド


サブコンポーネントにエラーが発生した場合に呼び出され、エラーをキャプチャしてfablack UIを表示できます.
static getDerivedStateFromError(): State {
  return { hasError: true };
}

render() {
  const { hasError } = this.state;
  const { children } = this.props;

  if (hasError) return fallback UI
  
  return children;
}

ComponentDidCatch()ライフサイクルメソッド


上記のgetDerivedStateFromError()ライフサイクルメソッドと同様に、サブコンポーネントにエラーが発生した場合に呼び出すのに使用されますが、エラー情報などの副作用を記録するのに使用されます.
getDervivedStateFromErrorとComponentDidCatchの違いを知りたければ、Brian Vaughnの回答内容を直接確認できます.
https://www.reddit.com/r/reactjs/comments/9lp0k3/new_lifecycle_method_getderivedstatefromerror/e79elpl/
私の場合、このメソッドではerrorタイプに基づいてtoastメッセージを呼び出す副作用が使用されます.
componentDidCatch(error: Error, errorInfo: ErrorInfo) {
  if (error instanceof CustomError) error.activateHandler();
}

Error Boundaryでの配置


Error Boundaryの原因を考えてみましょう.エラーが発生してアプリケーション全体が中断されるのを防ぐため、開発者の意図に応じてどこにでも配置できます.
私の場合、エラーを処理するためにYoutube APIを呼び出すコンポーネントの上にError Boundaryを配置します.
<Styled.SearchResultWrapper>
  <Styled.MainTitle>검색 결과</Styled.MainTitle>
  <ErrorBoundary fallback={<Error />}>
    <SearchResultContainer
      keyword={keyword}
      handleSelectMusic={handleSelectMusic}
      />
  </ErrorBoundary>
</Styled.SearchResultWrapper>

最終コード

import React, { Component, ErrorInfo, ReactElement, ReactNode } from 'react';
import CustomError from '../../../utils/customError';

interface Props {
  children: ReactNode;
  fallback: ReactElement;
  isReload?: boolean;
}

interface State {
  hasError: boolean;
}

class ErrorBoundary extends Component<Props, State> {
  state: State = {
    hasError: false,
  };

  static getDerivedStateFromError(): State {
    return { hasError: true };
  }

  componentDidCatch(error: Error, errorInfo: ErrorInfo) {
    if (error instanceof CustomError) error.activateHandler();
  }

  resetBoundary = () => {
    this.setState({ hasError: false });
  };

  reloadBoundary = () => window.location.reload();

  render() {
    const { hasError } = this.state;
    const { children, fallback, isReload } = this.props;

    if (hasError)
      return React.cloneElement(fallback, {
        refresh: isReload ? this.reloadBoundary : this.resetBoundary,
      });

    return children;
  }
}

export default ErrorBoundary;

Reference


  • https://reactjs.org/docs/error-boundaries.html

  • https://www.reddit.com/r/reactjs/comments/9lp0k3/new_lifecycle_method_getderivedstatefromerror/e79elpl/