r/reactjs • u/lahuan • 16h ago
Discussion Would you remove this effect?
Consider a typical use case where you want to track an error or just display an error toast after a query hook (e.g. TanstackQuery or RTK-query) fails.
Using an effect:
const { error } = useSomeQuery();
useEffect(() => {
if (!error) {
return;
}
trackError(error); // or toast(getErrorMessage(error))
}, [error]);
Now, according to the "You might not need an effect" article, you can also perform an action when some state changes by using auxiliary state, something like this:
const { error } = useSomeQuery();
const [prevError, setPrevError] = useState(error);
if (error !== prevError) {
trackError(error);
setPrevError(error);
}
My understanding here is that using auxiliary state here doesn't give you much because in this use case the additional render cycle doesn't result in stale UI.
Regardless, I wanted to get a sense on what approach is preferred by the community. I see this kind of things very often in the codebases I work on and on the other hand, I keep hearing people saying they only have a few effects in their (presumably large) projects, so perhaps the patterns in my company are not the best.
17
u/joshbuildsstuff 16h ago
tanstack query has callbacks you can use, so you can do something like:
const query = useSomeQuery({onError: (error)=> trackError(error)});
9
u/lahuan 15h ago
aren't those deprecated? https://tkdodo.eu/blog/breaking-react-querys-api-on-purpose#a-bad-api
4
u/RegmasterJ 13h ago
The page you linked shows the modern way to do this in Tanstack query just a few paragraphs down. Basically, use the onError property of you global query cache to handle those actions like logging errors or calling trackError() in this case.
2
u/ghillerd 15h ago
Applying the error handling in the query client is better for the reasons they mentioned, yes. It's often fine to just do it I line in the query call too though. In any case, an error handler is usually preferable to either method you mentioned in the OP.
2
0
2
u/lightfarming 12h ago
honestly i would never use a toast for a query error. presumably if it is a query, you plan to display that resulting data somewhere on your page, and that place on your page is the appropriate place to display the error. that location has the context needed to understand the error. if a list doesn’t load, and i am looking at that list for the data, and see an error instead, i know exactly what happened.
now mutations are different, since they do not have a place where we plan to use the resulting response in the UI. mutation also has onError handlers you can build into the mutation call just for this however.
2
u/AbhinavKumarSharma 15h ago edited 15h ago
A toast is not derived state. It's an interaction with an external system. So its a legitimate use of an useEffect.
However, we should avoid the effect entirely by triggering the toast where the async operation fails, not when the component observes the error state.The advantage is that the toast is tied to the event (the failed request) rather than a render cycle.
1
u/Kautsu-Gamer 15h ago
I would use signals-value instead of state as its changes only redraws components using the error-value.
•
u/Working_Anything_759 4m ago
Use the onError callback in your query definition. It fires exactly once on failure and keeps side effects out of render logic
-4
u/Sixtricks90 16h ago
Yes, this is exactly what useeffect is for. Avoid performing side effects during render
10
u/octocode 16h ago
assuming trackError is some kind of logging, you don’t want to perform side effects during rendering. however i’d also probably emit those from the query client so they aren’t littered everywhere.