Invalidate queries doesn't work [React-Query]

Viewed 12360

I'm trying to invalidate queries every times users press button "likes" to refresh all queries but without success so far despite following the docs.

I have a component that get data :

  const {
    data: resultsEnCours,
    isLoading,
    isError,
  } = useQueryGetEvents("homeencours", { currentEvents: true });

This is a custom hook which look like this :

const useQueryGetEvents = (nameQuery, params, callback) => {
  const [refetch, setRefetch] = React.useState(null);
  const refetchData = () => setRefetch(Date.now()); // => manual refresh
  const { user } = React.useContext(AuthContext);
  const { location } = React.useContext(SearchContext);

  const { isLoading, isError, data } = useQuery(
    [nameQuery, refetch],
    () => getFromApi(user.token, "getEvents", { id_user: user.infoUser.id, ...params }),
    // home params => "started", "upcoming", "participants"
    {
      select: React.useCallback(({ data }) => filterAndSortByResults(data, location, callback), []),
    }
  );

  return { data, isLoading, isError, refetchData };
};

export default useQueryGetEvents;

And I have another component "ButtonLikeEvent" which allow the user to like or unlike an event:

import { useMutation, useQueryClient } from "react-query";
import { postFromApi } from "../../api/routes"; 
...other imports


const ButtonLikeEvent = ({ item, color = "#fb3958" }) => {
  const queryClient = useQueryClient();
  const {
    user: {
      token,
      infoUser: { id },
    },
  } = React.useContext(AuthContext);

  const [isFavorite, setIsFavorite] = React.useState(item.isFavorite);
  const likeEventMutation = useMutation((object) => postFromApi(token, "postLikeEvent", object));
  const dislikeEventMutation = useMutation((object) =>
    postFromApi(token, "postDislikeEvent", object)
  );

  const callApi = () => {
    if (!isFavorite) {
      likeEventMutation.mutate(
        { id_events: item.id, id_user: id },
        {
          onSuccess() {
            queryClient.invalidateQueries();
            console.log("liked");
          },
        }
      );
    } else {
      dislikeEventMutation.mutate(
        { id_events: item.id, id_user: id },
        {
          onSuccess() {
            queryClient.invalidateQueries();
            console.log("disliked");
          },
        }
      );
    }
  };

  return (
    <Ionicons
      onPress={() => {
        setIsFavorite((prev) => !prev);
        callApi();
      }}
      name={isFavorite ? "heart" : "heart-outline"}
      size={30}
      color={color} //
    />
  );
};

export default ButtonLikeEvent;

Every time an user click on that button I'd like to invalidate queries (because many screens shows the like button).

The console.log is displayed on success but the queries are not invalidate.

Any idea ?

thanks

6 Answers

Also, there is one more reason that was not mentioned before:

If you used enabled option in useQuery than such queries are ignored by invalidateQueries. From docs:

https://react-query.tanstack.com/guides/disabling-queries

The query will ignore query client invalidateQueries and refetchQueries calls that would normally result in the query refetching.

I used

const queryClient = new QueryClient();

instead of

const queryClient = useQueryClient();

new QueryClient() creates a new react-query Client(which is usually passed to a context wrapped over your App), this should be done only once.

wheres useQueryClient returns a reference to the value that the react-query Client context wrapped around your app provides.

The two most common issues why query invalidation is not working are:

  • keys are not matching, so you are trying to invalidate something that doesn't exist in the cache. Inspecting the devtools helps here. Oftentimes, it's an issue with number/string (for example, if an id comes from the url, where it is a string, but in your key, it's a number). You can also try manually clicking the invalidate button in the devtools, so you will see that invalidation per-se works.

  • the queryClient is not stable across re-renders. This happens if you call new QueryClient() inside the render method of a component that then re-renders. Make sure that the queryClient is stable.

Both Samil and Eliav ideas combined worked for me:

  1. QueryClient is only for initializing the QueryClientProvider.
const queryClient = new QueryClient();
  1. useQueryClient is used everywhere else.
const queryClient = useQueryClient();

QueryClient should be instantiated on the top of your app. (app.js or index.js)

Sample

import { QueryClient, QueryClientProvider } from 'react-query';

const queryClient = new QueryClient();
ReactDOM.render(
    <QueryClientProvider client={queryClient}>
    <App />
    </QueryClientProvider>,
document.getElementById('root'));

In my case, all I had to do was await the promise that invalidateQueries returns before navigating away (using react-router).

Related