Prevent Caching on a specific RTK Query Endpoint
Asked Answered
B

6

11

I am using rtq query and i have an endpoint that takes azure-ad oid from the global store and makes a query to the backend to check if the user exists on the backend to check if the user exists. If the user exists then I redirect the user to the dashboard else I do not redirect the user.

The problem is that despite trying to prevent caching on that endpoint, it still uses the cached data and by the time the real data comes from the server, the redirect has already happened. Below are some of the steps I have taken to prevent this from happening.

  1. Using refetch
  2. Setting refetchOnMountOrArgChange: true,
  3. Setting keepUnusedDataFor: 0.0001 to invalidate the cache almost immediately

The point is that I do not want this endpoint to use any cached data.

Below is my component:

 const [isSignedIn] = useIsSignedIn();
  const history = useHistory();
  const dispatch = useAppDispatch();
  const ongraphLogin = async (role: string) => {
    if (Providers.globalProvider.login) {
      dispatch(setloginType(role));

      await Providers.globalProvider.login();
    }
  };
  const userState = useAppSelector(state => state.userState);

 
  console.log(userState?.currentUser?.id);
  const { data, error, isLoading, refetch } = useGetUserByOidQuery(userState?.currentUser?.id, {
    skip: isSignedIn,
    refetchOnMountOrArgChange: true
  });
  
  useEffect(() => {
    refetch();
    // console.log(res);
    if (isSignedIn) {
      console.log('I am in');
      // Check if the user exists in the ndovysystem
      if (data?.status === 'success') {
        console.log(data);
        history.push('/user');
      } else if (userState.loginType === 'volunteerRegistration') {
        history.push('/register/volunteer');
      } else if (userState.loginType === 'menteeRegistration') {
        history.push('/register/mentee');
      }
    }
  }, [isSignedIn, data]);

Below is the endpoint

import { ndovuAPI } from './ndovuAPI';

export const ndovuUserAPI = ndovuAPI.injectEndpoints({
  endpoints: builder => ({
    getUserByOid: builder.query({
      query: (oid: string) => `/users/oid/${oid}`,
      keepUnusedDataFor: 0.0001
    })
  })
});

// Export hooks for usage in functional components
export const { useGetUserByOidQuery} = ndovuUserAPI;

Kindly help me solve this.

Barograph answered 12/11, 2021 at 19:56 Comment(0)
H
11

Hmm. You can't really prevent caching of queries, but you could make that a mutation - by default even two mutations with the same arguments never share a cache entry.

Henceforward answered 12/11, 2021 at 21:40 Comment(5)
I have faced the same issue, If I use mutation I can't use skip, refetchOnMountOrArgChange, isLoading, isSuccess, etc.. right?Iqbal
Is there any other solution for that too?Iqbal
@DanielprabhakaranN since the whole point of RTK Query is to cache data, I guess the correct answer would in the end be to just use fetch for this. You cannot circumvent core functionality.Henceforward
there are use cases where a particular endpoint of an api should bypass the default aggressive caching behavior. Indeed there are other bypasses and possible modifications built into the caching options of RTK Query... potentially this is down to the poor api design of other services, however having a separate fetch implementation for a single route also is non-optimalTaite
@ßiansorÅ.Ålmerol I have honestly no idea what you are talking about here... Can you make a new question where you ask an actual question and lay down your assumptions? It seems like you are jumping to some conclusion here and I have no idea what thought process brought you there.Henceforward
W
12

You can pass timestamp as an argument of the query. That's what I did to prevent caching on mounting of the component.

Like this

const timestampRef = useRef(Date.now()).current;
const {data = [], isFetching} 
    = useGetChatMessagesQuery({id: chatId, lastMessageId, sessionId: timestampRef});
Woodshed answered 14/2, 2022 at 14:9 Comment(0)
H
11

Hmm. You can't really prevent caching of queries, but you could make that a mutation - by default even two mutations with the same arguments never share a cache entry.

Henceforward answered 12/11, 2021 at 21:40 Comment(5)
I have faced the same issue, If I use mutation I can't use skip, refetchOnMountOrArgChange, isLoading, isSuccess, etc.. right?Iqbal
Is there any other solution for that too?Iqbal
@DanielprabhakaranN since the whole point of RTK Query is to cache data, I guess the correct answer would in the end be to just use fetch for this. You cannot circumvent core functionality.Henceforward
there are use cases where a particular endpoint of an api should bypass the default aggressive caching behavior. Indeed there are other bypasses and possible modifications built into the caching options of RTK Query... potentially this is down to the poor api design of other services, however having a separate fetch implementation for a single route also is non-optimalTaite
@ßiansorÅ.Ålmerol I have honestly no idea what you are talking about here... Can you make a new question where you ask an actual question and lay down your assumptions? It seems like you are jumping to some conclusion here and I have no idea what thought process brought you there.Henceforward
P
4

Use 2nd argument as false in useLazyQuerySubscription or useLazyQuery

const [triggerGetUsers, { isLoading, error }] = useLazyGetUsersQuery();
 


const handleGetUsers = async (reqBody) => {

const { data: usersData, isLoading } = await triggerGetUsers(reqBody, false);

};

References: https://redux-toolkit.js.org/rtk-query/usage/queries#hook-types

  1. useLazyQuery

Returns a tuple with a trigger function, the query result, and last promise info. Similar to useQuery, but with manual control over when the data fetching occurs. Note: the trigger function takes a second argument of preferCacheValue?: boolean in the event you want to skip making a request if cached data already exists.

  1. useLazyQuerySubscription

Returns a tuple with a trigger function, and last promise info. Similar to useQuerySubscription, but with manual control over when the data fetching occurs. Note: the trigger function takes a second argument of preferCacheValue?: boolean in the event you want to skip making a request if cached data already exists.

Pettitoes answered 10/1, 2023 at 14:13 Comment(0)
C
2

This works

const { data, isFetching, refetch } = useSkillsListQuery(undefined, {
  refetchOnMountOrArgChange: 3600, // in seconds
});

This causes the query to invalidate the cache in 3600secs (1hr) and refetch automatically on component remount.

You can also use refetch to manually trigger a refetch which will invalidate the cache.

Contraception answered 25/2 at 17:38 Comment(0)
C
1

For my case I have a scenario which registers the user in data base the very first time they login with a 3rd party OAuth. But when the said component loads asynchronously which relies on user being in the db, I added a hook with refetch to check if the user is in db at that point. const { refetch } = useFetchUserQuery(authUserId);(useFetchUserQuery is the rtk query endpoint) const userInDb = (await refetch(authUserId).unwrap()); If user exists all the logged in functionality is made available if not just the default functionality. The refetch hook is dependent on userid and signed in status change. This project is in javascript

Cosgrove answered 5/2, 2023 at 23:34 Comment(0)
S
0

Whenever I want to disable the cache for a specific endpoint I use the already mentioned keepUnusedDataFor paremeter and set it to 0 (not 0.0001).

I am not sure if this was not working properly when this question was asked, but it currently is working perfectly fine for me with Redux Toolkit version 2.2.3.

Savitt answered 21/6 at 9:14 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.