Refetching queries does not work - React Query
Asked Answered
C

3

10

I'm trying to refetch some queries after one success but it's not working!

I used two ways to handle it by using refetchQueries() / invalidateQueries()

1- onSuccess callback

export const useMutateAcceptedOrder = () => {
  const queryClient = useQueryClient();
  return useMutation(
    ['AcceptedOrder'],
    (bodyQuery: AcceptedOrderProps) => acceptOrder(bodyQuery),
    {
      onSuccess: () => {
        console.log('success, refetch now!');
        queryClient.invalidateQueries(['getNewOrders']); // not work
        queryClient.refetchQueries(['getNewOrders']); // not work
      },
      onError: () => {
        console.error('err');
        queryClient.invalidateQueries(['getNewOrders']); // not work
      },
    },
  );
};

second way

 const {mutateAsync: onAcceptOrder, isLoading} = useMutateAcceptedOrder();
 const acceptOrder = async (orderId: string) => {
    const body = {
      device: 'iPhone',
      version: '1.0.0',
      location_lat: '10.10',
      location_lng: '10.10',
      orderId: orderId,
      os: Platform.OS,
      source: 'mobile',
      token: userInfo.token,
    };
    await onAcceptOrder(body);
    queryClient.refetchQueries(['getNewOrders']); // not work
    queryClient.invalidateQueries(['getActiveOrders']); // not work
    handleClosetModalPress();
  };

sample of query I wanted to refetch after the success

export const useNewOrders = (bodyQuery: {token: string | null}) => {
  console.log('token>>', bodyQuery.token);
  return useQuery(['getNewOrders'], () => getNewOrders(bodyQuery), 
  {
    enabled: bodyQuery.token != null,
  });
};

App.tsx

const App: React.FC<AppProps> = ({}) => {
  const queryClient = new QueryClient();
  if (__DEV__) {
    import('react-query-native-devtools').then(({addPlugin}) => {
      console.log('addPlugin');
      addPlugin({queryClient});
    });
  }

 
  useEffect(() => {
    RNBootSplash.hide({fade: true}); // fade
  }, []);


  return (
    <GestureHandlerRootView style={{flex: 1}}>
      <QueryClientProvider client={queryClient}>
        <BottomSheetModalProvider>
          <AppContainer />
        </BottomSheetModalProvider>
      </QueryClientProvider>
    </GestureHandlerRootView>
  );
};

export default App;

--

EDIT

So after using the react-query-native-devtools Debug tool, I can't see any query in the first tab recorded in the debugger! Although the data fetched well.

So I guess that's why the refetch did not work in this case!

Any query in the first tab I can't refetch it again

Steps to reproduce:

  • open App - Active Tab (first tab)
  • check the status of the queries
  • nothing recorded in the debugger
  • Navigate to any other screen/tab
  • Check the status of queries

all screen queries recorded in the debugger

Cheap answered 12/12, 2022 at 9:0 Comment(7)
Read the docs please. tanstack.com/query/v4/docs/guides/invalidations-from-mutations You need to provide a queryKey property for invalidateQueries.Feeze
@Feeze it's already exist ['getActiveOrders']Cheap
The docs use it like these though queryClient.invalidateQueries({ queryKey: ['todos'] }). whereas you're just passing them queryClient.refetchQueries(['getNewOrders']);Feeze
@Feeze same thing not worksCheap
What error does it show? Try to do it without creating any extra custom hooks first. Start with a clean slate of react query. And go through the docs for information. It seems you're also not using query keys properly as shown in docs tanstack.com/query/v4/docs/guides/query-keys. Are you following a tutorial or something?Feeze
@OliverD I was facing the same issue just now - did you try using queryClient.invalidateQueries({queryKey: ['getNewOrders']})? I just had to call it this way, refetchQueries wasn't even requiredCurb
@Curb yes i tried this way, but the same issue still :(Cheap
J
9

Per https://tkdodo.eu/blog/react-query-fa-qs#2-the-queryclient-is-not-stable:

If you move the client creation into the App component, and your component re-renders for some other reason (e.g. a route change), your cache will be thrown away:

Need to init queryClient like that:

const [queryClient] = React.useState(() => new QueryClient())

Jesicajeske answered 22/1, 2023 at 18:43 Comment(0)
C
2

I was facing the same issue and haven't been able to find a proper solution for this, however I have found a hacky workaround. You just call your refetch function or invalidate queries inside a setTimeout.

Costplus answered 30/1, 2023 at 8:38 Comment(1)
As it’s currently written, your answer is unclear. Please edit to add additional details that will help others understand how this addresses the question asked. You can find more information on how to write good answers in the help center.Fissionable
W
0

This is a relatively old question, but I ran into the same problem. I ended up solving my problem in a few ways:

#1 I changed my update API endpoints so that after modifying a record, it sends the whole new record back, and I end up doing queryClient.setQueryData to update the local cache.

#2 Even though queryClient.invalidateQueries is plural, I switched everything to singular invalidations per query key.

#3 Grepped my code base to ensure there is only 1 instance of new QueryClient and everywhere else is using useQueryClient

#4 Last and perhaps least, I added .then() to invalidateQueries just in case the async code was somehow never being executed.

Note https://tanstack.com/query/v4/docs/react/guides/query-invalidation#query-matching-with-invalidatequeries The invalidate query call only seems to work if I added the mentioned fetchType param.

Here is the documentation for https://tanstack.com/query/v4/docs/react/reference/QueryClient#queryclientsetqueriesdata

Below is a full example of what I did above.

const _updateCharacter = useMutation<Character, Error, Character>({
        mutationFn: (character: Character) => api.update_character(character),
        onSuccess: (updated_character) => {
            queryClient.setQueryData(
                ['book', activeBook.id, 'character', updated_character.id],
                () => updated_character
            )

            queryClient
                .invalidateQueries({
                    queryKey: ['book', activeBook.id, 'characters'],
                    exact: true,
                    refetchType: 'active'
                })
                .then()
        },
        onError: (error) => {
            console.log(error)
        }
    })

This is for a detailed book inventory management system. The goal is to update the details for a specific character BUT, in addition, update a list of all characters to reflect a name change, note word count, and the last updated field.

Not relevant, but every Character record has an internal id primary key and an exposed snowflake unique identifier, so that's why I can get away with just passing the record to the API without its associated book.

I hope this helps someone else and saves them from slowly losing their mind as nothing seems to work.

White answered 17/7, 2023 at 21:25 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.