反応誤差境界とフォールバックコンポーネントによるユーザフレンドリなエラー


もし私たちのUIがエラーの上でクラッシュするのを防ぎたいし、また、このエラーを友好的に示すためにフォールバックUIを持っていないなら、我々は、我々のアプリケーションの重要な部分を包み込んで、それの中のどこでもJavaScript誤りを捕える反応誤り境界要素を使用することができます.
型スクリプトによる完全なコード例here .

カスタムエラー境界コンポーネントの作成


エラー境界は、2つの特別なライフサイクルメソッドにアクセスできるクラスコンポーネントとして作成されます.
  • static getDerivedStateFromError() これは、更新のUIを表示する状態の更新.
  • componentDidCatch() エラー情報のログに使用します.
  • class ErrorBoundary extends React.Component {
      state: State = {error: null}
    
      static getDerivedStateFromError(error) {
        return {error}
      }
    
      componentDidCatch(error, errorInfo) {
        logErrorToMyService(error, errorInfo);
      }
    
      render() {
        const {error} = this.state
        if (error) {
          return <this.props.FallbackComponent error={error} />
        }
        return this.props.children
      }
    }
    
    この例ではFallbackComponent エラーがエラーをキャッチし、エラーを外部サービスにログ出力している場合にレンダリングされます.
    ErrorBoundationコンポーネントをアプリケーションで使用するには、いくつかのエラーに遭遇する可能性のあるコンポーネントをラップする必要があります.この例では、APIからデータを取得するコンポーネントをラップし、エラーメッセージを示すフォールバックコンポーネントを渡しました.
    <ErrorBoundary
      // use key as a workaround for resetting the errorboundary state
      key={circuitName}
      FallbackComponent={CircuitErrorFallback}
    >
      <CircuitContent />
    </ErrorBoundary>
    
    function CircuitErrorFallback({error}) {
      return (
        <div role="alert">
          <h3>Something went wrong...</h3>
          <p>{error.message}</p>
        </div>
      )
    }
    
    The <CircuitContent /> 何かが我々のAPI呼び出しで間違っているならば、コンポーネントは誤りを投げます:
    function CircuitContent({circuitName}) {
      const [state, setState] = useState<>({
        status: 'idle',
        circuit: {},
        error: null,
      })
      const {status, circuit, error} = state
    
      useEffect(() => {
        if (!circuitName) {
          return
        }
        setState(prevState => ({...prevState, status: 'pending'}))
        fetchCircuit(circuitName).then(
          circuit => {
            setState(prevState => ({...prevState, status: 'resolved', circuit}))
          },
          error => {
            setState(prevState => ({...prevState, status: 'rejected', error}))
          },
        )  
      }, [circuitName])
    
      if (status === 'idle') {
        return <CircuitIdle />
      } else if (status === 'pending') {
        return <CircuitLoading />
      } else if (status === 'rejected') {
        // throw error to be handled by error boundary
        throw error
      } else if (status === 'resolved') {
        return <CircuitDetails circuit={circuit} />
      }
    
      throw new Error('Something went really wrong.')
    }
    
    ErrorBoundationはこのエラーをキャッチし、フォールバックコンポーネントをレンダリングします.

    反応誤差境界の利用


    我々自身のエラー境界要素をつくることは、かなりまっすぐですreact-error-boundary パッケージ私たちのアプリと私たちのエラー境界をリセットし、UIの状態を復元するための機能を使用します.
    import {ErrorBoundary} from 'react-error-boundary'
    
    <ErrorBoundary
      onReset={handleReset}
      resetKeys={[circuitName]}
      FallbackComponent={CircuitErrorFallback}
    >
      <CircuitContent circuitName={circuitName} />
    </ErrorBoundary>
    
    さあ、フォールバックコンポーネントをボタンを使って拡張します.
    function CircuitErrorFallback({ error, resetErrorBoundary }) {
      return (
        <div role="alert">
          <h3>Something went wrong...</h3>
          <p>{error.message}</p>
          <button onClick={resetErrorBoundary}>
            Try again
          </button>
        </div>
      )
    }
    
    結果のエラーUIは以下のようになります.

    結論


    我々は、インターフェイスをインタラクティブに保つためにエラー境界を使用してアプリケーションのさまざまな部分をラップしてクラッシュを防ぐことができます.TypesScriptによって気づかれることさえできなかったエラーを捕えている間、これは発展段階の間、我々に利益を与えることもできます.

    CREATE - REMART APPでの使用法についての注意


    エラー境界がエラーをキャッチしたとしても、CRAは開発モードでエラー情報でオーバレイを表示するかもしれません.Create Applicationアプリのこの動作を変更するための回避策がありますが、私はそれがunecessaryだと思うので、あなたはオーバーレイを閉じるために' ESC 'を押すことができますので、これはとにかく生産ビルドで表示されません.

    Axiosでエラーメッセージを処理するヒント


    Axiosは、“サーバーが404のステータスコードを応答したようなカスタムメッセージでエラーをスローします.”API呼び出しが失敗したとき.このカスタムメッセージをAPIレスポンス本体の実際のエラーメッセージに変更するか、別のものにマップすることもできます.
    const api = axios.create({baseURL: 'https://api.backend.com'})
    api.interceptors.response.use(
      response => response,
      error => {
        if (error.response.data.message) {
          error.message = error.response.data.message
        }
        return Promise.reject(error)
      },
    )
    
    このポストのアイデアはEpicCertからの反応フックワークショップのレッスンから来ました.読書ありがとう!