Open sanduluca opened 2 weeks ago
We still don't have a reproduction on this. My take is that you somehow save a reference to the refetch
method of the first few renders instead of calling refetch
on the latest result - you are likely working with a stale closure somewhere.
I notice one common thing with #2889. We are using lodash debounce library with refetch. Here is the example of how we use it.
We define a runDebouncedRetry
function that is the result of lodash debounce
outside of react context to keep a stable reference. runDebouncedRetry
receives a func as a parrameter that is invoked immediately.
import React from "react";
import { View } from "react-native";
import debounce from "lodash/debounce";
import { Button, Typography } from "./core";
const runDebouncedRetry = debounce((func: () => void) => func(), 1000, {
leading: true,
});
export default function ErrorDataLoad({
retry,
message,
debounceEnabled = true,
isRefreshing,
}) {
return (
<View style={{ flex: 1 }}>
<View style={{ flex: 1, alignItems: "center", justifyContent: "center" }}>
<View style={{ marginTop: 30 }}>
<Typography variant="accent24">Ups. something happend</Typography>
</View>
<View style={{ marginTop: 22 }}>
<Typography variant="regular14" color="n700">
{message}
</Typography>
</View>
</View>
<View style={{ paddingHorizontal: 20 }}>
<Button
loading={isRefreshing}
label={"Retry"}
type="Main"
onPress={() => {
if (debounceEnabled) {
return runDebouncedRetry(retry);
}
return retry();
}}
/>
</View>
</View>
);
}
We have some crashes reported in our app with the message "Cannot refetch a query that has not been started yet.". We see the crashed in Firebase Crashlytics. I could not repeat the the crash myself. I searched here the issues with the same problem, but could not find a possible solution . The closest related issue seems to be #2889
Here is the crash stats for Android (we have the same and for iOS)
Here is the screen code example we have:
Example Screen 1
```tsx import { useState } from "react"; import { ScrollView } from "react-native"; import Barcode from "react-native-barcode-builder"; import { Layout, Header } from "components"; import RefreshControl from "components/core/RefreshControl"; import ErrorDataLoad from "components/ErrorDataLoad"; import { useGetInfoQuery } from "store/info"; export function Screen() { const [isRefreshing, setIsRefreshing] = useState(false); const { data, isLoading, error, refetch } = useGetInfoQuery( undefined, { refetchOnMountOrArgChange: true, } ); const onRefresh = () => { setIsRefreshing(true); refetch().finally(() => setIsRefreshing(false)); }; return (
}
>
{isLoading ? (
) : error ? (
) : data ? (
) : null}
);
}
```
Example Screen 2
```tsx import { useState } from "react"; import { FlatList, View } from "react-native"; import { RatingCell, Layout, Header } from "components"; import RefreshControl from "components/core/RefreshControl"; import { useGetRatingGroupsQuery, useGetRatingQuery } from "store/rating"; import { LoadingOverlay } from "components/LoadingOverlay"; import ErrorDataLoad from "components/ErrorDataLoad"; export function RatingScreen() { const { data: rating, error: ratingError, isLoading: isLoadingRating, refetch: refetchRating, } = useGetRatingQuery(undefined, { refetchOnMountOrArgChange: true }); const { data: ratingGroups, error: ratingGroupError, isLoading: isLoadingRatingGroup, refetch: refetchRatingGroup, } = useGetRatingGroupsQuery(undefined, { refetchOnMountOrArgChange: true }); const [isRefreshing, setIsRefreshing] = useState(false); const onRefresh = () => { setIsRefreshing(true); Promise.all([refetchRating(), refetchRatingGroup()]).finally(() => { setIsRefreshing(false); }); }; const error = ratingError || ratingGroupError; const isLoading = isLoadingRating || isLoadingRatingGroup; return (
{isLoading ? (
) : error ? (
) : rating && ratingGroups && ? (
<>
}
refreshControl={
}
/>
>
) : null}
);
}
```