Stale || Fetching doesn't actually represent when operations are in progress while offline
seanaye opened this issue ยท 5 comments
Describe the bug
When using the offlineExchange there is no way to tell if values are still being loaded or not. Based on the documentation a union between fetching || stale
should represent if there is a potentially new value still being loaded, however this is not the case.
In the below repro turn off the network and open console. You will see the following
fetching and stale are both false and the data is null
then a values comes back while fetching and stale are still both false.
This means there is effectively no way to tell if a query is 'settled' or not when the user is offline.
It appears like this occurs with all relevant cache policies as well.
Reproduction
https://stackblitz.com/edit/github-cnyjhe?file=src%2FApp.jsx
Urql version
"dependencies": {
"@urql/core": "^4.2.0",
"@urql/exchange-graphcache": "^6.4.0",
"graphql": "^16.6.0",
"react": "^18.2.0",
"react-dom": "^18.2.0",
"urql": "^4.0.6"
},
Validations
- I can confirm that this is a bug report, and not a feature request, RFC, question, or discussion, for which GitHub Discussions should be used
- Read the docs.
- Follow our Code of Conduct
When the user is offline we settle the query and put it on a queue ๐ isn't there a network-error in the result though?
Will try to check the repro and our relevant code later today or tomorrow
After thinking about this, when the user goes offline we don't really want to show these as in progress as they're operations that got aborted by the network going offline and we put it in an internal queue for when the user comes back online. Depending how folks do loading, i.e. Suspense for a query could become problematic or if the whole form is blocked out the user can doubt whether it's worth navigating away from the page it could confuse the user... I personally think marking it as resolved and leaving the UX concerns up to the application to highlight "user you are offline" is correct in this context
The main issue here for me is that its impossible to determine if urql is still doing something in the background. Assuming we want to redirect to a new page if some information cannot be found in the cache while the user is offline, there is no information surfaced by urql to tell us that it is safe to redirect.
There is no loading state
There is no stale state
There is no error state
There is no data
It appears like the query has been settled, and then some new information comes in.
Currently we just use a timeout after everything is settled and just wait to see if new data comes. This is not really a solution just a bandaid. If we rely on navigator.onLine
this is still just a bandaid solution because we will just need to set a timeout and see if any extra information comes.
Hiya ๐
Just to highlight the problem here.
It's impossible for us to indicate that someone is offline, hence the default that has been chosen. Even if there was a reliable property or signal for us to detect this, network requests may still fail.
In other words, there isn't a 100% fail safe method of detecting that a device is offline due to network instability issues.
To then explain what's going on, from a bindings perspective it's important to note that fetching: false
only indicates that no result is actively being waited for.
Meanwhile, stale: true
means that an operation has been initiated and a current result is expected to be updated.
However, when offline, even if we set stale: true
there is nothing to be gained here. All that it's telling you is that something is still actively being fetched, which may or may not fail.
There are other ways to indicate this to the user, but doing so at the site of the bindings rather than globally doesn't gain you much imho.
Assuming we want to redirect to a new page if some information cannot be found in the cache while the user is offline, there is no information surfaced by urql to tell us that it is safe to redirect.
This sounds more like a schema design issue to me though.
You have neither a value (like a special object type on a union) nor null
here to check for.
So, i'm not sure what you're expecting to check for, but this state seems unambiguous to me. Even if you have an offline cache, when you fail to retrieve an up-to-date value, you have no choice but to trust the stored/cached value and to use it.
Basically, it's irrelevant that the request failed if you have no retry on it and are offline. Either you got some data you can act on or you don't ๐
This is where some opinions shine through, but tl;dr a complete solution would likely have a special signal/value associated with onOnline
on storage that corresponds to the device being online again.
However, to put it short, without us injecting an opinion on how that online/offline state is kept, while also handling that any fetch request can fail regardless of this value/network state due to the device being offline and this value being out-of-date, there simply isn't something useful that the UI bindings side can surface.
To make it obvious, even if we set stale
back to true
, you would then be unaware and uncertain when it may do so. Just like a result being able to come in any time, this is also something that could then happen any time.
Closing this because of inactivity and the question itself being answered. Feel free to re-open or continue this discussion