Skip to content

Query with refetchOnFocus in combination with redux-persist: data is not refetched upon app launch after hard close #4259

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

Closed
fikkatra opened this issue Mar 8, 2024 · 4 comments

Comments

@fikkatra
Copy link

fikkatra commented Mar 8, 2024

We are using redux-toolkit in combination with redux-persist in a React Native app. We use it to keep the user's data available when they are offline.

We pass the following options to the query hook:

{
  refetchOnFocus: true,
  refetchOnReconnect: true,
}

To make this work in React Native, we pass a custom callback to setupListeners as mentioned here.

Once the data has been fetched from the backend, it's persisted in async storage. So far so good. When the user launches the app, the expected behavior is as follows:

  • If the device is offline, the persisted data is shown
  • If the user is online, the data is refetched. The previously persisted data may show briefly while the refetch is in progress, but eventually, the updated data should be shown (and persisted).

While the first case (offline) works nicely, the second doesn't: the persisted data is shown but the data is never updated from the backend. We observe this behavior when fully initializing the app, e.g. after a hard close. We see the following in the logs:

  • onFocus is dispatched from setupListeners callback
  • REHYDRATE action is received, containing the previously persisted data
  • no backend calls were made
  • the data remains stale :-(

I'd expect that onFocus would trigger a backend call, but it doesn't.

When we deactivate the app and open it again (without hard-closing it), we do see the desired behavior:

  • onFocus is dispatched from setupListeners callback
  • no REHYDRATE action is received
  • a backend request is fired
  • the data is updated

Of course, we want it to display the updated data, regardless if the app was hard or soft closed.

One extra thing worth mentioning: we are using react-navigation, which keeps screens mounted even though they are not focused. This implies there is always an active query subscription.

I have a feeling I'm doing something wrong, but I'm not sure what. What am I missing here?

@reduxjs/[email protected]
[email protected]
[email protected]

@phryneas
Copy link
Member

phryneas commented Mar 8, 2024

You could just add something like setTimeout(onFocus, 100) to that code snippet.
It seems that you just get things happening in a bad order - you want to rehydrate first, then dispatch onFocus. The problem here seems to be that in RN, rehydration apparently is asynchronous.

@fikkatra
Copy link
Author

fikkatra commented Mar 8, 2024

Ok, thanks for your reply. I think another way to fix it, would be to do a manual refetch upon app start, using the query hook? That way, we don't depend on the 100ms timeout, which could potentially still go wrong. Or will a manual refetch also fail to make a back end request, if it happens to be executed before the rehydration?

@phryneas
Copy link
Member

phryneas commented Mar 8, 2024

Maybe initialize the listeners after you successfully finished hydration? It seems weird to me that you render your app before hydration finished - as a result, there might be new requests to the server happening that otherwise would not be necessary.

@fikkatra
Copy link
Author

For our use cases, the ideal behavior would be to hydrate from the cache first, then perform a server request to refetch the data, reverting back to the cached data in case something goes wrong with the request (e.g. network unavailable). Of course, this might not be the intended behavior of the library.

In any case, our problem might indeed be solved by wrapping the app in a PersistGate to postpone rendering until hydration finished, like you said. Then, we can execute the refetch from a component within the PersistGate, which is then guaranteed to happen after hydration finished. So the intention is slightly different: we want to perform some server requests after hydration finished, rather than avoiding unnecessary server calls.

Closing this as we found a solution, thanks for the support!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants