Komail Fayazbakhsh
Komail Fayazbakhsh

Reputation: 374

Is it possible to re-render a component after updating cache with React Query?

In The root component, I received this data from the cache.

  const queryClient = useQueryClient();
  const data = queryClient.getQueryData('prototypes');

In another component, after firing a function, I changed the data on cache (with optimistic update). Although the data was changed in cache and shown in Devtools, new data in root component was not showing and component didn't refresh.

how can I re-render a component after changing cache?

Before, I used this way to get data in Ssr mode in Nextjs.

export const getServerSideProps = wrapper.getServerSideProps(
  (store) =>
    async ({ req }) => {
      const queryClient = new QueryClient();
      await queryClient.prefetchQuery('prototypes', getPrototypes);

      return {
        props: { dehydratedState: dehydrate(queryClient) },
      };
    }
);

In a child component, I used useQuery hook to get data.

  const { data: prototypes }: { data: FilterPrototypesByDateQuery } = useQuery(
    'prototypes',
    getPrototypes
  );

Although data was existed in cache, when this component was mounted, in network I saw that a new request to get prototypes was fired.

In other child component, when i liked a prototype, i used optimistic update to update cache. But i saw that a new request for prototypes was fired again.

 const { mutate: likePrototype } = useLikePrototypeMutation({
    onMutate: async (like) => {
      const previousPrototype: FilterPrototypesByDateQuery =
        queryClient.getQueryData('prototypes');

      const newState = produce(previousPrototype, (draft) => {
        const index = draft.prototype_getPrototypes.result.items.findIndex(
          (item) => item.id === prototypeId
        );
        if (index > -1) {
          draft.prototype_getPrototypes.result.items[index].isLiked = true;
        }
      });
      queryClient.setQueryData('prototypes', newState);
      return { previousPrototype };
    },
    onSettled: () => {
      queryClient.invalidateQueries('prototypes');
    },
  });

Upvotes: 3

Views: 5872

Answers (1)

Jakub Kotrs
Jakub Kotrs

Reputation: 6244

The first step when you want a query to not fetch new data ever again, is to set its cache and stale times to infinity. This makes RQ remember the data forever but also always return from cache.

const { data: prototypes } = useQuery('prototypes', getPrototypes, {
  cacheTime: Infinity,
  staleTime: Infinity,
});

The next step is that you should not be manually invalidating the query. When you change it using setQueryData, it will be updated.

const { mutate: likePrototype } = useLikePrototypeMutation({
  onMutate: async (like) => {
    // ...
    // this causes the component using that query to update
    queryClient.setQueryData('prototypes', newState);
    // ...
  },
  // no onSettled here
  // just rollback in onError
});

Upvotes: 4

Related Questions