T
TanStack17mo ago
rare-sapphire

refetchOnReconnect with Suspense query

Hey, guys. I'm using React Native and I have a question, not sure if it's a bug. When using useSuspenseQuery with Suspense (obviously), ErrorBoundary and QueryErrorResetBoundary, if I access a screen without internet connection, an error will be thrown since API can't be reached, but after reconnecting, the error is NOT automatically reset. That scenario would work fine with useQuery. I made some research and I found there is a resetKeys option of react-error-boundary that I could change whenever connection status change. If that is actually the final solution, I think we should make it clear in the docs, especially on the React Native guide (https://tanstack.com/query/latest/docs/framework/react/react-native#online-status-management)
React Native | TanStack Query React Docs
React Query is designed to work out of the box with React Native, with the exception of the devtools, which are only supported with React DOM at this time. There is a 3rd party Flipper plugin which you can try: https://github.com/bgaleotti/react-query-native-devtools
12 Replies
correct-apricot
correct-apricot17mo ago
Why do you get an error boundary because of a paused query?
rare-sapphire
rare-sapphireOP17mo ago
I'm not sure. I guess it's because I have retry: 0 in defaultOptions. That's the only difference for release mode, where I have retry: 1 and the Suspense fallback is shown instead. while query is paused. Regarding the Suspense fallback, I thought of keeping the onlineManager always online, to always run the queryFn, but I would lose the refetchOnReconnect feature...
correct-apricot
correct-apricot17mo ago
which networkMode do you use? With the default, you should see the suspense boundary
rare-sapphire
rare-sapphireOP17mo ago
The default, unchanged
correct-apricot
correct-apricot17mo ago
then maybe show a reproduction please. if you are offline and a query wants to fire, it goes in paused state, which should trigger the suspense boundary independent of the retry option
rare-sapphire
rare-sapphireOP17mo ago
Maybe it's something specific to react native or my setup. I'll try dig more into it and make a repro But for the suspense case, do you have an idea on how to customize the paused state ui, instead of just showing the loading ui? With useQuery I would check for isPaused before isLoading, but that's not possible in this case.
correct-apricot
correct-apricot17mo ago
you can check the online state in the fallback with the onlineManager
rare-sapphire
rare-sapphireOP17mo ago
Maybe I'm extending this thread too much, but I'd like to know your opinion on the following: I created a generic component to abstract ui states for a suspense query, something like that:
export function QueryBoundary(props: Props) {
const [isOnline, setIsOnline] = React.useState(onlineManager.isOnline());
React.useEffect(() => onlineManager.subscribe(setIsOnline));

const fallback = props.loading ?? <DefaultFallback />;
const ErrorFallback = props.error ?? DefaultErrorFallback;

return (
<QueryErrorResetBoundary>
{({ reset }) => (
<ErrorBoundary
onReset={reset}
fallbackRender={({ error, resetErrorBoundary }) => (
<ErrorFallback error={error} retry={resetErrorBoundary} />
)}
resetKeys={[isOnline]}
>
<Suspense fallback={fallback}>{props.children}</Suspense>
</ErrorBoundary>
)}
</QueryErrorResetBoundary>
);
}
export function QueryBoundary(props: Props) {
const [isOnline, setIsOnline] = React.useState(onlineManager.isOnline());
React.useEffect(() => onlineManager.subscribe(setIsOnline));

const fallback = props.loading ?? <DefaultFallback />;
const ErrorFallback = props.error ?? DefaultErrorFallback;

return (
<QueryErrorResetBoundary>
{({ reset }) => (
<ErrorBoundary
onReset={reset}
fallbackRender={({ error, resetErrorBoundary }) => (
<ErrorFallback error={error} retry={resetErrorBoundary} />
)}
resetKeys={[isOnline]}
>
<Suspense fallback={fallback}>{props.children}</Suspense>
</ErrorBoundary>
)}
</QueryErrorResetBoundary>
);
}
I can change the Suspense fallback based on "isOnline" value like you said, and that solves my problem for now, but what if I had suspense queries with different network modes (like 'always', where the paused ui wouldnt make sense)? I managed to reproduce the issue (https://codesandbox.io/p/sandbox/bold-monad-nykkwz?file=%2Fsrc%2FApp.js%3A22%2C17). Looks like the problem is with persister
correct-apricot
correct-apricot17mo ago
if I had suspense queries with different network modes
good question, I don't have an answer to that atm what do I need to do in that sandbox and what is expected to happen ?
rare-sapphire
rare-sapphireOP17mo ago
Without the persister, the suspense fallback is shown as expected when offline. With the persister set, the error boundary is triggered instead (when offline) looking at the docs, I noticed that the networkMode is actually set to 'offlineFirst' when using persister. I just didnt't understand why the issue only happens with retry set to 0
correct-apricot
correct-apricot17mo ago
oh, right right, the docs also explain why we need that. I think that's expected then, and you need at least one retry
rare-sapphire
rare-sapphireOP17mo ago
I think my solution for now will be setting networkMode: 'always' for every suspense query, and handle the internet error in error boundary

Did you find this page helpful?