I'm using Apollo to interact with a GraphQL server in a Web application written in React. I'm trying to implement error handling in the application and relying on apollo-link-error for this.
Now, there are 2 categories of errors that I need to handle:
errors that can be handled locally in the component which does the Apollo query or mutation, i.e. an invalid form field on which I need to show contextual error information
errors that can be handled globally, for example by showing a toast notification displaying error details somewhere in the page
Clearly, once the error is handled locally I need it to not be handled globally, because it doesn't make much sense to show an error message next to a form field and a generic error via a toast message.
The first stumbling block I encountered when trying to implement this is that the global error handling logic triggers before the local error handling logic, which prevents me from being able to intercept the error locally and then find a way to prevent the global logic from kicking in.
I created codesandbox example which sets up an ApolloClient in the simplest possible way, uses the http and error links, and uses the react-apollo Query component to do a query for a resource that doesn't exist, generating an error.
I'm handling the error both in the onError callback of the Query component (so local error handling), and in the apollo-link-error handler (so global error handling), and printing to the console the errors.
It shows that the global error handling logic kicks in before the local error handling. I would need it to be the other way around.
I've published a library called react-apollo-network-status which handles exactly this use case. Let me know if it's useful to you!
The opt-in/-out behaviour for treating some errors locally is implemented by setting a context variable on the operation which can be read in the error link.
Related
Does anyone know why I can't handle server error with try{}catch(){}?
There is a console error although I am trying to handle fetch errors within the fetch context and outside of it?
Please refer to the attached image to get a better understanding: Fetch request
I am using react with redux-saga but I think there is nothing related with redux.
I tried executing that same function in the component itself and it still happens.
I'm using nextjs for quite a while now. I relied on _error.js page provided by nextjs when there is any error. In their doc here, it is specified to use errorboundary. Should I continue relying or next.js _error.js page or add errorboundary?
_error.js page is just a customization when the application throws a 500 error.
500 errors are handled both client-side and server-side by the Error component. If you wish to override it, define the file pages/_error.js and add the following code:
Error Boundaries are a React JS concept - Think of them as fallback components that can receive the error and display it or you can handle it yourself - It's considered as a best practice
They cover completely different areas of the stack.
I've been experimenting with components that do a react-cache style thing and do web service calls right in the render method, throwing a promise up to a React.Suspense component and re-rendering when the data is there. They call a web service, check the response, and either render or throw an error up to an error boundary depending on the response. I've noticed that whenever an error is thrown in a component, it renders twice. The first time the callstack looks normal, and the second time the callstack includes calls to invokeGuardedCallbackDev and invokeGuardedCallback, which seem to have something to do with React ensuring that errors appear in the console even when "caught" by an error boundary in a dev build.
I can reproduce this with react and react-dom 16.8.6 by just rendering a component like this: https://codesandbox.io/s/components-that-throw-render-twice-i26qc.
I'm wondering why this happens, because it's causing the components to re-fetch data from the web service, re-throw another promise, and results in an "Uncaught Promise" error appearing in the console.
This seems to be caused by a recent change in react/react-dom. If you revert both to version 16.0.0, you will see that it only renders the component once. See: https://codesandbox.io/s/components-that-throw-render-twice-03fdb
Looking at the version history, there seem to be a couple of bugs fixed relating to error handling in React, so it seems like this re-rendering is a result of a workaround for one of those bugs.
However, this should not be a problem for your app, as the render function should be pure (no side effects) in React apps. So basically, React can call your render function anytime it wants/needs to.
To work around this, you should avoid relying on the component not re-rendering and instead use an effect hook or similar to only fetch when certain props/state change.
Source: https://github.com/facebook/react/issues/16130#issuecomment-521637592
I think the error boundary is not actually catching the thrown error.
From https://reactjs.org/docs/error-boundaries.html:
Note
Error boundaries do not catch errors for:
Asynchronous code (e.g. setTimeout or requestAnimationFrame callbacks)
Asynchronous code includes Promises in this case.
See also https://reactjs.org/docs/error-boundaries.html#how-about-event-handlers:
Error boundaries do not catch errors inside event handlers.
If you need to catch an error inside event handler, use the regular JavaScript try / catch statement.
I try to add a global error handler on my react app. That work perfecly but I have only one problem when I use saga and a fetch call. Below a simple example :
The error (in setModules) is swallowing (I think by the fetch promise) but I dont understand where and how to correct this behavior. Is this case, the error is never send to the error or unhandledrejection events and google devtool reports that error from the "getModules" function. I tried many changes (like using done instead of then and remove the catch) but no miracle.
You have a catch statement into another catch... Try putting the (error handling logic) try/catch statement in your getModules saga only et viola.
I highly recommend to manage error into the sagas only, not in your gateways functions, that way to avoid this issues.
I'm using server side rendering for my React app but can't wrap my head around the logic for showing error pages when something goes wrong.
For example:
User requests /article/123
Something goes wrong while fetching the article
I would like to show a 500 error page
The server side part was easy. I tell React-Router to serve my error component. So far so good.
But when the page is served, the client-side javascript is executed and it takes over rendering. React-Router see the url /article/123 and loads the component that shows the article (but fails since the data is not present..)
Is there a way to let the client-side know that we want to show the error component instead?
The only think I could think of is the following: Add the error to the global redux state. Before rendering a component, check if the error is present in the global state and show the error component instead.. But the downside of this is that you have to implement that checking logic in all of your components. There should be some kind more elegant way to fix this..
There's a few different ways to implement client-side error handling; I find using Higher Order Components work best. You would create a wrapper component that checks for errors from the server response. If it finds one, serve the appropriate error page. If the HOC doesn't detect an error, serve the component the user originally requested.
Here's a great explanation on how to implement HOC:
https://medium.com/#franleplant/react-higher-order-components-in-depth-cf9032ee6c3e