This issue was moved to a discussion.
You can continue the conversation there. Go to discussion →
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
blog/react-query-error-handling #29
Comments
Thanks for yet another great article! |
Thanks, this is really helpful! I now understand error boundaries a lot better. If I use onError in the queryClient to globally catch all errors as you suggest, is there any way to get the query key from react query for error reporting purposes? Or am I limited to just the returned error message itself? |
@ptmkenny the signature of
so it gets the whole |
Wow, I only thought |
Awesome artcile, thank you. |
I guess it depends on what you want to do when a query errors on the server side. Generally, I'd say since you create a separate QueryClient on the frontend / backend, you can do the same and potentially share the code. Keep in mind that per default, only successful queries are sent to the client though. |
Cool article. Particularly good is that you mentioned Error Boundaries for 5xx. Sometimes I hear Error Boundaries being used to handle errors, but rarely do anyone mention that they are only meant to adhere to the Fail-Fast Principle. |
Hi, Reading this thread, I found out that a "query" param is available for the Looking at the react-query typings (QueryObserverOptions), i see only :
Tried to bypass typings by casting options to Some clarifications would be very sweet from you guys :) |
@lamaland Seems like you’re mixing up the global onError callback on the queryCache, which does receive the query as second parameter, and the callback on observer level (onError of useQuery), which only receives the error. |
@TkDodo, my bad, you are absolutly right 👍 |
Was trying like this :
Using the querycache way works as expected :) |
So if I do this either inside of QueryClient or QueryCache:
the other default options provided by react-query are gone (for example default refetch when the window becomes active). How can one add a global error handler without overwriting the out-of-the-box defaults? |
No, the default options you provide are merged with the default options, so unless you set refetchOnWindowFocus to false, it will stay on. Further, this is not the way to provide a global onError handler. As the article tried to explain, you have to set onError on the QueryCache or the MutationCache for a truly global handler. |
Ok, so if I do this the refetchOnWindowFocus works but obviously i don't get any errors set into state since it's the first time the app loads and query.state.data is undefined:
but if I do this the errors are set globally, but the refetchOnWindowFocus no longer works:
can you let me know what i'm missing? |
Please create a codesandbox reproduction so that I can get the full picture. |
Superb article, thanks! |
@vago it's a good question, and one that doesn't have a clearly defined answer imo, as it depends on the kind of data that you display. Is stale data better than an error screen, and can background errors be discarded or displayed otherwise? If so, my first check is always In other cases, if I'm getting an error after 3 retries, maybe there is a real error and I don't want my users to see, and interact with, the stale ui. In that cases doing the status check is perfectly fine. I've also written about that here: https://tkdodo.eu/blog/status-checks-in-react-query |
Thank you for the reasoning. Makes sense. |
How would you show a specific toast error notification tho, that is eg. different for every query? I think the best way to do this is, within |
hey @danielbartsch 👋 glad to see you're still reading my blog 😄. In v3.29.0, we added the I think it would be a good solution for your use-case. Example:
before that, the only "workaround" was to make that message part of the |
great solution! However Also is there a way of ensuring typescript types for this, other than wrapping |
yep, we'd need to add that. Would you like to contribute it?
Thought about this when we introduced it, but decided against it. We've done that for the query key, and we needed to add a 4th generic to useQuery, |
for readers of this blog: it's done |
Thanks for letting us know about what is the right way to handle errors if using react-query. But I have a question related to global onError callback handling mechanism. Suppose if we need to send two pieces of information to the toast so that it can display both a. error message b. error title. a. error message is what we we are getting from server. Good enough! Thanks |
@Ramandhingra as discussed above, you can use the |
I read the "meta" feature and it is clear to me how to inject a title. Thanks I have few other Qs for you. Could you pl. answer them: a. Is it possible to execute the onError both at a global and local level for a given query or mutation. For example, use global onError to display toast and local onError to handle local logic, for example navigate to this particular route if error occurs. b. Is it possible to execute global onError conditionally, like I do not want to show a toast for some errors. I think it might be achieved by adding a boolean key/value in the 'meta' object and check if it is set to true, then only display toast. Right? c. Here is an example that displays toast locally:
Now as advised by you, we can also display toasts at a global level indicating that some validation failed. Keeping this in view, I am looking for code something like this:
As of now, I don't know react-query much. So pl. confirm if the if/else logic is correct. Is this pattern okay with you, or would you advise local onError handler for each query and mutation placed immediately after the server response in the local functions themselves? d. If using react-query, is there any way to check isLoading at a global level.. just like react-query has provided us with the global onError callback? I guess there is no such event handler that is fired just before the query/mutation execution is about to take place, named something like onBefore. If not there, could you pl. add it in next release? I know that React.Suspense can be used but it is kinda experimental and React does not recommend to use it. How about your opinion, can we use Suspense in a production app where there will be about 100 queries and mutations resulting in a lot of boilerplate if Loading is handled locally? e. In order to display toast for failed background queries, we are writing a global onError callback for "QueryCache". For the same reason, it needs to be written for MutationCache as well. Am I right? f. Do you recommend a single Error Boundary component for the entire app? I am asking this because I read it somewhere that it is not advisable to have a single global Error Boundary. If really not advisable, consider this typical component hierarchy where QueryClientProvider is at the top. Now if we wrap the QueryClientProvider component inside the Error Boundary component, the 5xx errors thrown by react-query are handled by the global Error Boundary nonetheless.
Thanks for your guidance and time. |
@TkDodo |
@Ramandhingra sorry for taking a bit longer. For posterity: I have answered the questions on a discussion in the react-query repo. |
Yes, I got to know by email that you answered my queries over there. Thanks |
@TkDodo |
you can definitely create the QueryClient inside the component, but make sure to memoize it correctly with either You can read about that here: https://tkdodo.eu/blog/use-state-for-one-time-initializations
|
@TkDodo |
@drmeloy I would need to see an example please. Usually state management of toast notifications is outside of react-query so I have no idea what could cause that behavior |
Sure! I have collection and management of toasts being done through a react context provider. It provides a function
You'll notice the Here is my Query Provider file:
My observations so far:
|
@TkDodo As a follow-up I put a console.log inside the QueryCache's onError:
Of the two error toasts that are being generated I'm only seeing a console log for the second one (the one I am unable to dismiss) |
@TkDodo I tested this implementation on the onError of the individual queries and the error only pops up once rather than twice. |
If you only see the log inside onError once, that means it's only called once. The other error toast must come from somewhere else. A codesandbox reproduce would be best. |
Ok, so you handle all errors with toast popups, but what if you want to display an alert on specific page within specific component? Then global QueryCache callback is practically unusable if you don't have some global state management? I am frustrated that community doesn't already have clear consensus about handling all 4 possible states (success, loading, error, empty) that should maybe even be built into framework and not let every developer reinvent it in every app. It's common requirement for every possible app. |
Not sure this should be the takeaway from the blogpost. I've shown 3 ways of handling errors:
And I've stated that I personally prefer The problem about clear consensus is that it is mostly a ux question that has to be answered on a case-by-case basis. Some errors are so severe that it is necessary to unmount the whole component tree and only show the error. Other errors, especially once where you already have data to be shown instead, might be less severe so they can be handled differently. Some maybe can even be ignored altogether. |
This issue was moved to a discussion.
You can continue the conversation there. Go to discussion →
React Query Error Handling | TkDodo's blog
After covering the sunshine cases of data fetching, it's time to look at situations where things don't go as planned and "Something went wrong..."
https://tkdodo.eu/blog/react-query-error-handling?utterances=7f4ddb690c1dc8b340d5813cNdwcVH1AM%2B%2F%2BNm%2F7plRpwS567856B8nwLLdwEWUkZUEMc0yQTcWPy9sNBGdEH2aBVE4P4kvQZA92KLug9dFRt6gblMCB9Gikd9jEf3ZczDWkqifI7DcRPO7bs4M%3D
The text was updated successfully, but these errors were encountered: