React Native refetching on refocus and/or remount #296
-
Hey! So I started working on a revision of an project of mine, and my plan was to codeshare a bunch between the (new) app and web, and use react-query to replace the current data loading strategies. I started off with creating the new RN app, but found that My suggestion: either directly support this RN usecase, or add a separate option e.g. One direct way to tackle the problem codewise (but probably not the best), would be to just redefine Any ideas? |
Beta Was this translation helpful? Give feedback.
Replies: 10 comments 16 replies
-
React Navigation is one of the available options when it comes to React Native. This means that ReactQuery cannot assume that it's used in every app. Therefore it won't be supported out of the box. But I've created this small library https://github.com/cherniavskii/react-query-navigation-native to help integrate react-query with react-navigation.
|
Beta Was this translation helpful? Give feedback.
-
Super awesome that you provided a nice example solution so fast, usable out-of-the-box. Thanks 👍 I still wonder though whether it might not make sense to pull into the main library anyway. I know the N:N library cross-supporting is a bad road in principle. Nonetheless, react-navigation is (I believe) the community standard library that all new RN users will float towards. And if react-query wants to popularize itself as an easy-to-use out-of-the-box data loading library, then it might make sense. (Putting it under an extra option, maybe even in a more general way, is also a valid way.) |
Beta Was this translation helpful? Give feedback.
-
Nice! Any solutions for react-native-navigation or guidance to getting that to work? |
Beta Was this translation helpful? Give feedback.
-
I use this and add in and in pages I want to refetch data #296 (reply in thread) |
Beta Was this translation helpful? Give feedback.
-
In case u want to refetch only when you focus your screen (without infinity loop) because a lot of people want to do this export const useRefetchOnFocus = (refetch = () => {}, canRefetch = true) => {
const [isScreenFocused, setIsScreenFocused] = useState(false);
useFocusEffect(() => {
setIsScreenFocused(true); // when i focus the screen
return () => setIsScreenFocused(false); // when i quit the screen
});
/* the screen still always active in cache so we need to check that the screen is focused in a use effect
to dispatch the refetch only one time to avoid the infinity loop*/
useEffect(() => {
if (isScreenFocused && canRefetch) {
refetch();
}
}, [canRefetch, isScreenFocused, refetch]);
}; and in your screen const { data, refetch } = useAccount();
useRefetchOnFocus(refetch); |
Beta Was this translation helpful? Give feedback.
-
|
Beta Was this translation helpful? Give feedback.
-
One specific edge case for react-navigation we faced was that we have verifications from web app and we were redirecting user to web but once when we return back to the screen we were redirecting from were not working with onFocus effect as app was going in background.
|
Beta Was this translation helpful? Give feedback.
-
This is my solution, I've needed to add staleTime to my code, so in case someone will be looking on how to do it: // useRefetchOnFocus.ts
import { useFocusEffect } from '@react-navigation/native'
import { useCallback, useRef } from 'react'
import { useAppStateActive } from './useAppStateActive'
export const useRefetchOnFocus = (
refetch: () => void,
/**
* Time after refetch function will be refetched
* If you don't want to cache the values, you can set this to `0`
* **Default**: 1 minute / 60 seconds (60 * 1000)
*/
time = 60 * 1000
) => {
const isFirstRun = useRef(false)
const lastFetchTime = useRef(Date.now())
useFocusEffect(
useCallback(() => {
if (!isFirstRun.current) {
isFirstRun.current = true
return
}
// Prevents refetching if the last fetch was less than 1 minute ago
// Boosts performance and prevents unnecessary API calls
if (Date.now() - lastFetchTime.current < time) {
return
}
lastFetchTime.current = Date.now()
refetch()
}, [refetch, time])
)
useAppStateActive(refetch, false)
} // useAppStateActive.ts
import { useCallback, useEffect, useRef } from 'react'
import { AppState, AppStateStatus } from 'react-native'
/**
* This hook will run on every app state change from background to foreground
*/
export function useAppStateActive(onChange = () => {}, runOnMount = true) {
const appState = useRef(AppState.currentState)
const _handleChange = useCallback(
(nextAppState: AppStateStatus) => {
if (appState.current.match(/inactive|background/) && nextAppState === 'active') {
onChange()
}
appState.current = nextAppState
},
[onChange]
)
useEffect(() => {
const subscription = AppState.addEventListener('change', _handleChange)
if (runOnMount) {
onChange()
}
return () => {
subscription.remove()
}
}, [_handleChange, onChange, runOnMount])
} Then you are using it like this: const { data, refetch } = useUser();
// This will be refetched on screen focus and when changing app state to active
useRefetchOnFocus(refetch); |
Beta Was this translation helpful? Give feedback.
-
Does anyone have any thoughts on the best way to achieve a refetch upon screen re-focus (i.e. user starts on screen A, navigates to screen B, then back to screen A) without using the manual My logic for wanting this is that by using So, if that makes any sense, then the only way I can think of achieving this is to instead force a re-render of the screen upon re-focus so that the screen's useQuery hook is called again. Then the staleTime within the Query's own logic can be respected and a refetch only happens if the staleTime is exceeded. Any thoughts on this most welcome - especially if I've misunderstood something about how RQ works. |
Beta Was this translation helpful? Give feedback.
-
import { ThunkDispatch, createAction } from "@reduxjs/toolkit"; export const onFocus = createAction("__rtkq/focused"); let initialized: Boolean = false; export function setupListeners(
}; const webDefaultHandler = () => {
}; return customHandler |
Beta Was this translation helpful? Give feedback.
React Navigation is one of the available options when it comes to React Native. This means that ReactQuery cannot assume that it's used in every app. Therefore it won't be supported out of the box.
But I've created this small library https://github.com/cherniavskii/react-query-navigation-native to help integrate react-query with react-navigation.
Features:
AppState
)useQuery
hook (by usinguseFocusEffect
from React Navigation)