反応のエラーを扱うために、Error Error境界を使用してください

9965 ワード

このコードは何が悪いのですか.
import * as React from 'react'
import ReactDOM from 'react-dom'

function Greeting({subject}) {
  return <div>Hello {subject.toUpperCase()}</div>
}

function Farewell({subject}) {
  return <div>Goodbye {subject.toUpperCase()}</div>
}

function App() {
  return (
    <div>
      <Greeting />
      <Farewell />
    </div>
  )
}

ReactDOM.render(<App />, document.getElementById('root'))
あなたが生産にそれを送るならば、あなたのユーザーは悲しさの白いスクリーンを得るつもりです:

CREATE TROP APPのエラーオーバーレイ(開発中)でこれを実行すると、次のようになります.

問題は、被験者のプロップ(文字列として)を渡すか、被験者のプロップの値をデフォルトにする必要があります.明らかに、これは工夫されていますが、ランタイムエラーはすべての時間に起こります.したがって、そのようなエラーを優雅に扱うのは良い考えです.では、このエラーをしばらくの間残しておきましょう.このような実行時エラーを処理するために、どのようなツールが反応しているかを見ましょう.
トライ/キャッチ?
この種のエラーを処理するナイーブアプローチはtry/catchを追加することです.
import * as React from 'react'
import ReactDOM from 'react-dom'

function ErrorFallback({error}) {
  return (
    <div role="alert">
      <p>Something went wrong:</p>
      <pre style={{color: 'red'}}>{error.message}</pre>
    </div>
  )
}

function Greeting({subject}) {
  try {
    return <div>Hello {subject.toUpperCase()}</div>
  } catch (error) {
    return <ErrorFallback error={error} />
  }
}

function Farewell({subject}) {
  try {
    return <div>Goodbye {subject.toUpperCase()}</div>
  } catch (error) {
    return <ErrorFallback error={error} />
  }
}

function App() {
  return (
    <div>
      <Greeting />
      <Farewell />
    </div>
  )
}

ReactDOM.render(<App />, document.getElementById('root'))
それは「動く」
何か悪いことがあった.Cannot read properties of undefined (reading 'toUpperCase')何か悪いことがあった.Cannot read properties of undefined (reading 'toUpperCase')しかし、それは私のばかげているかもしれませんが、私はtry/catchブロックで私のアプリ内のすべてのコンポーネントをラップしたくない場合はどうですか?通常のJavaScriptでは、単にtry/catchで呼び出し元の関数をラップできます.ここで試してみましょう
import * as React from 'react'
import ReactDOM from 'react-dom'

function ErrorFallback({error}) {
  return (
    <div role="alert">
      <p>Something went wrong:</p>
      <pre style={{color: 'red'}}>{error.message}</pre>
    </div>
  )
}

function Greeting({subject}) {
  return <div>Hello {subject.toUpperCase()}</div>
}

function Farewell({subject}) {
  return <div>Goodbye {subject.toUpperCase()}</div>
}

function App() {
  try {
    return (
      <div>
        <Greeting />
        <Farewell />
      </div>
    )
  } catch (error) {
    return <ErrorFallback error={error} />
  }
}

ReactDOM.render(<App />, document.getElementById('root'))
残念ながら、これは動きません.そして、それは我々が挨拶と別れを呼ぶものでないからです.反応はそれらの関数を呼び出します.JSXでそれらを使用するとき、我々は単にタイプとしてそれらの機能で反応要素を作成しています.“アプリがレンダリングされている場合は、ここで呼ばれる必要がある他のコンポーネントが”という反応を伝えるしかし、実際にそれらを呼び出していないので、try/catchは動作しません.
try/catchは本質的に必須であり、とにかく私のアプリケーションのエラーを処理する宣言的な方法を好む.
エラー境界
これは、エラー境界機能が遊びに来るところです.“エラー境界”は、上記のようなランタイムエラーを処理するために書き込む特殊なコンポーネントです.コンポーネントがエラー境界であることを示します.
  • クラスコンポーネントでなければなりません🙁
  • それはGetDeriveStateFromErrorまたはComponentDidcatchのどちらかを実装しなければなりません.
  • 幸いにも、エラーの境界を反応させるエラーの境界コンポーネントを誰もがあなたがあなたの反応アプリでの実行時エラーを宣言的に処理するために必要なすべてのツールを与えるので、誰もが書き込む必要があります.
    したがって、Reaction Error境界を追加し、ErrorBoundaryコンポーネントをレンダリングします.
    import * as React from 'react'
    import ReactDOM from 'react-dom'
    import {ErrorBoundary} from 'react-error-boundary'
    
    function ErrorFallback({error}) {
      return (
        <div role="alert">
          <p>Something went wrong:</p>
          <pre style={{color: 'red'}}>{error.message}</pre>
        </div>
      )
    }
    
    function Greeting({subject}) {
      return <div>Hello {subject.toUpperCase()}</div>
    }
    
    function Farewell({subject}) {
      return <div>Goodbye {subject.toUpperCase()}</div>
    }
    
    function App() {
      return (
        <div>
          <ErrorBoundary FallbackComponent={ErrorFallback}>
            <Greeting />
            <Farewell />
          </ErrorBoundary>
        </div>
      )
    }
    
    ReactDOM.render(<App />, document.getElementById('root'))
    
    何か悪いことがあった.TypeError: Cannot read property 'toUpperCase' of undefinedエラー回復
    これについての良いことは、あなたがトライ/キャッチブロックを行うのと同じ方法で、ErrorBoundationコンポーネントについてほとんど考えられることです.あなたは多くのエラーを処理するために反応成分の束のまわりにそれを包むことができます、あるいは、あなたはより粒状のエラー処理と回復をするために木の特定の部分にそれを範囲指定することができます.エラーの境界線は、我々は同様にこれを管理するために必要なすべてのツールを与えます.
    より複雑な例を示します.
    function ErrorFallback({error, resetErrorBoundary}) {
      return (
        <div role="alert">
          <p>Something went wrong:</p>
          <pre style={{color: 'red'}}>{error.message}</pre>
          <button onClick={resetErrorBoundary}>Try again</button>
        </div>
      )
    }
    
    function Bomb({username}) {
      if (username === 'bomb') {
        throw new Error('💥 CABOOM 💥')
      }
      return `Hi ${username}`
    }
    
    function App() {
      const [username, setUsername] = React.useState('')
      const usernameRef = React.useRef(null)
    
      return (
        <div>
          <label>
            {`Username (don't type "bomb"): `}
            <input
              placeholder={`type "bomb"`}
              value={username}
              onChange={e => setUsername(e.target.value)}
              ref={usernameRef}
            />
          </label>
          <div>
            <ErrorBoundary
              FallbackComponent={ErrorFallback}
              onReset={() => {
                setUsername('')
                usernameRef.current.focus()
              }}
              resetKeys={[username]}
            >
              <Bomb username={username} />
            </ErrorBoundary>
          </div>
        </div>
      )
    }
    
    すべてのエラーを処理
    残念なことに、我々のエラー境界に手を出すことができない/反応しないいくつかの誤りがあります.反応ドキュメントを引用するには、次の手順に従います.
    エラー境界はエラーをキャッチしません:
  • イベントハンドラ
  • 非同期コード( settimeoutやrequestanimationframeコールバックなど)
  • サーバ側レンダリング
  • エラー・境界自体(その子供よりむしろ)で投げられるエラー
    ほとんどの場合、人々はいくつかのエラー状態を管理し、エラーの場合には何か別のものをレンダリングします.
    function Greeting() {
      const [{status, greeting, error}, setState] = React.useState({
        status: 'idle',
        greeting: null,
        error: null,
      })
    
      function handleSubmit(event) {
        event.preventDefault()
        const name = event.target.elements.name.value
        setState({status: 'pending'})
        fetchGreeting(name).then(
          newGreeting => setState({greeting: newGreeting, status: 'resolved'}),
          newError => setState({error: newError, status: 'rejected'}),
        )
      }
    
      return status === 'rejected' ? (
        <ErrorFallback error={error} />
      ) : status === 'resolved' ? (
        <div>{greeting}</div>
      ) : (
        <form onSubmit={handleSubmit}>
          <label>Name</label>
          <input id="name" />
          <button type="submit" onClick={handleClick}>
            get a greeting
          </button>
        </form>
      )
    }
    
    残念ながら、このような方法でエラーを処理するには2つの方法を維持しなければならないということです.
  • 実行時エラー
  • fetch挨拶エラー
  • 幸いにも、エラーの境界線も、これらの状況を支援するための単純なフックを露出反応します.ここでは、これを完全にサイドステップにする方法を示します.
    function Greeting() {
      const [{status, greeting}, setState] = React.useState({
        status: 'idle',
        greeting: null,
      })
      const handleError = useErrorHandler()
    
      function handleSubmit(event) {
        event.preventDefault()
        const name = event.target.elements.name.value
        setState({status: 'pending'})
        fetchGreeting(name).then(
          newGreeting => setState({greeting: newGreeting, status: 'resolved'}),
          error => handleError(error),
        )
      }
    
      return status === 'resolved' ? (
        <div>{greeting}</div>
      ) : (
        <form onSubmit={handleSubmit}>
          <label>Name</label>
          <input id="name" />
          <button type="submit" onClick={handleClick}>
            get a greeting
          </button>
        </form>
      )
    }
    
    したがって、私たちのfetch懇願約束が拒絶されるとき、HandleError関数はエラーと呼ばれて、エラー境界に反応します、それは通常のように最も近いエラー境界に伝播します.
    あるいは、エラーを与えるフックを使っているとしましょう.
    function Greeting() {
      const [name, setName] = React.useState('')
      const {status, greeting, error} = useGreeting(name)
      useErrorHandler(error)
    
      function handleSubmit(event) {
        event.preventDefault()
        const name = event.target.elements.name.value
        setName(name)
      }
    
      return status === 'resolved' ? (
        <div>{greeting}</div>
      ) : (
        <form onSubmit={handleSubmit}>
          <label>Name</label>
          <input id="name" />
          <button type="submit" onClick={handleClick}>
            get a greeting
          </button>
        </form>
      )
    }
    
    この場合、エラーがこれまで真の値に設定されている場合は、最も近いエラー境界に伝播されます.
    どちらの場合でも、以下のようなエラーを扱うことができます.const ui = (
    <ErrorBoundary FallbackComponent={ErrorFallback}>
    <Greeting />
    </ErrorBoundary>
    )
    そして今、それはあなたの実行時エラーだけでなく、fetchCampaignやUseValuationコードの非同期エラーを処理します.
    グッドラック.