facebook / relay

Relay is a JavaScript framework for building data-driven React applications.
https://relay.dev
MIT License
18.36k stars 1.82k forks source link

QueryRenderer timeout for poor offline conditions #2947

Open matt-dalton opened 4 years ago

matt-dalton commented 4 years ago

The problem We are trying to build an app that works under a variety of network conditions using Relay. We have handled the fully offline case (effectively 'when offline, use cache' - helped by the fantastic React Relay Offline library!).

This works well for most cases. However, a common situation is 'effectively offline'. This is where the phone technically has signal, but it is too weak to fetch any data.

For certain screens we would prefer to use the network-only fetchPolicy, because we need new data, and we don't want to show the cached data before new data arrives a few seconds later.

However, for these screens in 'effectively offline' conditions, we just see an infinite loading spinner.

Possible solution The behaviour I often see with other apps here (e.g. Spotify) is a query timeout. It will try and fetch data, then if it doesn't receive it, it will fall back to what's in the cache (if available).

To achieve this, would it make sense to add an optional timeout option for network-only fetchPolicys.

Is this something you have considered? Or am I missing another way of handling this situation?

zth commented 4 years ago

Hmm, couldn't you add this to your network cache config and handle it in your fetch function yourself? QueryRenderer takes a CacheConfig, that in turn take a metadata object: https://github.com/facebook/relay/blob/597d2a17aa29d401830407b6814a5f8d148f632d/packages/relay-runtime/util/RelayRuntimeTypes.js#L58

...you could probably add "timeout" there, and then look for that in your fetch function, and time the request out yourself to achieve the thing you want.

matt-dalton commented 4 years ago

Interesting....will play about and see if I can come up with a solution. Could be an interesting one to consider for Relay regardless? Assuming we feel the use-case is valid/common.

josephsavona commented 4 years ago

Per @zth’s suggestion, we recommend setting a timeout in your network later (fetch function). You can either make this a fixed timeout or make it configurable w CacheConfig metadata.

josephsavona commented 4 years ago

Reopening because just failing after a timeout doesn’t necessarily achieve the desired effect. It sounds like what you’re looking for is basically “network-only if there’s actually a network connection, otherwise store-only”. Today you’d have to manually detect the timeout and retry w store-only fetch policy. Let’s leave this open to consider how we could better support this.

matt-dalton commented 4 years ago

Is there not a way to imperatively use the store from within the fetch function? i.e. If timeout reached, get query from store? That was how I planned to try and build something . Haven't managed to get anything working yet, as I was struggling to get it working with other middleware we have.

zth commented 4 years ago

I wonder if you could create a custom hook "useFetchPolicyFromNetworkStatus" that checks the connection and returns the appropriate fetchPolicy? You could then pass that to QueryRenderer.

sibelius commented 4 years ago

My idea is to have a timeout on network, and if it hit the timeout we return data directly from store

matt-dalton commented 4 years ago

My idea is to have a timeout on network, and if it hit the timeout we return data directly from store

Yep, that's what I was thinking

morrys commented 4 years ago

This is the behavior that I implemented in react-relay-offline to handle the queries, in practice if there is no connection, any policy is modified in store-only.

The speech is different when the connection is there but it is not "good". With the NetInfo library it is possible to know the quality of the connection but I am of the idea that it is a difficult data to manage with respect to a definition of timeout.

These are the solutions I thought of:

in relay-hooks (2.0.0):

useQuery manages the ability to refresh by modifying fetchPolicy, this can be used as follows:

in react-relay-offline (1.0.0):

in relay-experimental:

An alternative could be to evolve Relay to manage the timeout parameter natively in hook / HOC and perform lookup in the store after the timeout expires. This allows you to "wait" for the request made via the network.

stale[bot] commented 3 years ago

This issue has been automatically marked as stale because it has not had recent activity. It will be closed if no further activity occurs. Thank you for your contributions.