web-dev-qa-db-ja.com

react-apollo useMutationフックによるエラーの処理

私はこの問題を回避しようと努力してきましたが、それに対する強力な答えは見つかりませんでした。 useMutationフックを使用してログインミューテーションを実行しようとしています。

TLDR;オプションで渡されたonErrorとuseMutationによって与えられたエラーの違いは正確に何なのか知りたい

これが私のコードスニペットです

const [login, { data, loading, error }] = useMutation(LOGIN_QUERY, {
        variables: {
            email,
            password
        },
        onError(err) {
            console.log(err);
        },
});

サーバー側では、ログインに使用するプリセット/ハードコードされたメールを使用していますが、Apolloや他のクライアントを使用していません。このログイン変異のリゾルバーでは、メールが同じでない場合はエラーをスローします

throw new Error('Invalid Email');

クライアント側(React)でこのエラーを処理したいと思います。しかし、私の懸念は、useMutationフックから返された「エラー」を使用して、この方法でエラーを表示しようとすると、

render() {
...
{error && <div> Error occured </div>}
...
}

エラーはUIで更新されますが、すぐにReactに、未処理の拒否(エラー)の画面が表示されます:Graphqlエラー:My-custom-error-message

しかし、useMutate関数にオプションで渡されたonErrorを使用すると、この画面は表示されず、エラーに対して何でも実行できます。

オプションで渡されたonErrorとuseMutationによって与えられたエラーの違いは正確に何であり、なぜReactがonErrorのときにエラー画面を表示するのかnot使用。

ありがとう!

9
d_bhatnagar

ApolloはそのAPIを通じて2種類のエラーを公開します:GraphQLエラーerrorsとともに、dataとして応答の一部として返されます、およびリクエストが失敗したときに発生するネットワークエラー。サーバーに到達できない場合、または応答ステータスが200以外の場合、ネットワークエラーが発生します。応答にerrorsが含まれているクエリでも、ステータスが200になる可能性があります。ただし、たとえば無効なクエリは、 400ステータスとApolloクライアントのネットワークエラー。

Apolloクライアントは、実際には変異エラーを処理するための4つの異なる方法を提供します。

1.)フックによって返されたmutate関数を呼び出すと、Promiseが返されます。リクエストが成功した場合、Promiseはサーバーから返されたdataを含むレスポンスオブジェクトにresolveします。リクエストが失敗すると、Promiseはエラーでrejectします。これが、コンソールに「未処理の拒否」メッセージが表示される理由です。拒否されたPromiseを処理する必要があります。

login()
  .then(({ data }) => {
    // you can do something with the response here
  })
  .catch(e => {
    // you can do something with the error here
  })

またはasync/await構文:

try {
  const { data } = await login()
} catch (e) {
  // do something with the error here
}

デフォルトでは、PromiseはGraphQLエラーまたはネットワークエラーのいずれかを拒否します。 errorPolicyignoreまたはallに設定すると、Promiseはネットワークエラーに対してonlyを拒否します。この場合、応答オブジェクトを介してGraphQLエラーにアクセスできますが、Promiseは解決します。

2.)上記の唯一の例外は、onError関数を指定した場合に発生します。この場合、Promiseは拒否せずに常に解決しますが、エラーが発生した場合、onErrorが呼び出され、結果としてエラーが発生します。設定したerrorPolicyもここに適用されます。onErrorは常にネットワークエラーに対して呼び出されますが、errorPolicyのデフォルトのnoneを使用する場合にのみGraphQLエラーで呼び出されます。 onErrorを使用することは、拒否されたPromiseをキャッチすることと同じです。エラーハンドラをmutate関数の呼び出しサイトからフックの呼び出しサイトに移動するだけです。

3.)mutate関数に加えて、useMutationフックは結果オブジェクトも返します。このオブジェクトは、ミューテーションの実行中に発生したエラーも公開します。上記で作成したエラーハンドラー関数とは異なり、このerrorオブジェクトはapplication stateを表します。この方法で公開されたerrorオブジェクトとdataオブジェクトの両方が、便宜上存在しています。彼らはこれを行うことと同等です:

const [mutate] = useMutation(YOUR_MUTATION)
const [data, setData] = useState()
const [error, setError] = useState()
const handleClick = async () => {
  try {
    const { data } = await mutate()
    setData(data)
  catch (e) {
    setError(e)
  }
}

このようなエラー状態は、UIにエラーがあるという事実を反映させたい場合に役立ちます。たとえば、突然変異がエラーなしで実行されるまで、要素の色を変更できます。上記のボイラープレートを自分で作成する代わりに、提供された結果オブジェクトを使用できます。

const [mutate, { data, error }] = useMutation(YOUR_MUTATION)

4.)最後に、 apollo-link-error を使用して、リクエストにglobalエラー処理を追加することもできます。これにより、たとえば、アプリケーションのどこでリクエストが発生したかに関係なく、エラーダイアログを表示できます。

アプリケーションでこれらのメソッドのどれを使用するかは、実行しようとしていることに大きく依存します(グローバルvsローカル、状態vsコールバックなど)。ほとんどのアプリケーションは、エラー処理の複数の方法を利用します。

23
Daniel Rearden