I'm trying to figure out a good error handling strategy and I'm hitting dead ends. I guess my hope is that I could somehow come up with a way to show a generic "something went wrong" toast or modal while keeping the UI in a state that can be still used to retry the operation but it seems like a pipe dream.
Error boundaries have only limited usefulness because they have their own state so you need to have a way to reset their internal state to re-render which is not very practical.
I would be curious to hear how the mainstream clojure frameworks handle errors. A cursory search doesn't bring up anything concrete.
There are different kinds of errors that require different handling
Validation errors, operational errors (e.g. backend is down), and coding errors
Probably more
It’s a good architectural problem
IME error boundaries are good at catching coding errors & operational errors (esp. with suspense), not good at catching validation errors
“Keeping the UI in a state that can be still used to retry the operation” what makes this hard?
> Error boundaries [...] need to have a way to reset their internal state to re-render which is not very practical this is an annoying thing about error boundaries. it forces you to unmount the component tree and remount it. TBD if this helps us toward better practices or not, but you can handle this by changing the key the error boundary has
for your toast idea, you could use an error boundary that doesn’t handle the actual error; rather, in its didCatch method you could signal the toast to appear, and then do nothing. or re-mount the children below it
Yeah errors is very much a complected term. HTTP tries to categorize them but it’s still messy.
> “Keeping the UI in a state that can be still used to retry the operation” > what makes this hard? With suspense for data fetching, what triggers the fetch might be far away, or the state of the UI might be subtly broken. Nothing a bit of discipline can’t fix of course, but it seems there’s not much discussion about this. Perhaps flux or relay have some opinions about this.
I think using declarative queries a la GraphQL does help here because you can scope the error to what actually uses the data being requested
GraphQL also allows fine-grained errors, i.e. some attributes may succeed and others can fail, so you can show errors for only components that depend on attributes that failed to resolve
I have one way of doing errors that so far is working out, but I am actually not certain if it's sane. 1. I have global state, but obviously everything namespaced so no collisions 2. Errors have their own top level namespace, otherwise it's duplicated down 3. this way I can check for errors, keep more than one error, but also just clear from anywhere anytime
I tried collecting, passing, keeping locally, all were problematic and buggy in the end.
So components can check for specific errors @ashnur ?
yeah, and some errors are less important, but sometimes I want a history of errors
so then I can put a vector under the same namespace the input or whatever I need it for is
but I think this stuff that I can't really use atoms like clojure intended it is a problem
We are using Suspense for data via reseda. It seems though that errors should be a top-level prop for components, next to data. Like your approach @ashnur. I’m just surprised that Clojure frontend frameworks don’t seem to have a story for this, as it’s something that’s hard to retrofit as I find out :)