Leo Messi
Leo Messi

Reputation: 6166

How to make a refetch wait for a POST in React-Query

There are two requests, a POST and a GET. The POST request should create data and after it has created that data, the GET request should fetch the newly created data and show it somewhere.

This are the hooks imported into the component:

  const { mutate: postTrigger } = usePostTrigger();
  const { refetch } = useGetTriggers();

And they are used inside an onSubmit method:

  const onAddSubmit = async (data) => {
    await postTrigger(data);
    toggle(); // this one and the one bellow aren't important for this issue
    reset(emptyInput); // 
    refetch();
  };

Tried to add async / await in order to make it wait until the POST is finished but it doesn't.

Any suggestions?

I added here the code of those 2 hooks if it's useful:

POST hook:

import { useMutation } from 'react-query';
 
import { ICalculationEngine } from '../constants/types';
import calculationEngineAPI from '../services/calculation-engine-api';
 
export const usePostTrigger = () => {
  const apiService = calculationEngineAPI<ICalculationEngine['TriggerDailyOpt1']>();
 
  const mutation = useMutation((formData: ICalculationEngine['TriggerDailyOpt1']) =>
    apiService.post('/trigger/DailyOpt1', formData)
  );
 
  return {
    ...mutation
  };
};
 
export default usePostTrigger;

GET hook:

import { useMemo } from 'react';
import { useInfiniteQuery } from 'react-query';
 
import { ICalculationEngine } from '../constants/types';
import { calculationEngineAPI } from '../services/calculation-engine-api';
export const TAG_PAGE_SIZE = 20;
 
export interface PaginatedData<D> {
  totalPages: number;
  totalElements: number;
  content: D[];
}
 
export const useGetTriggers = () => {
  const query = 'getTriggers';
  const apiService = calculationEngineAPI<PaginatedData<ICalculationEngine['Trigger']>>();
 
  const fetchTriggers = (pageNumber: number) => {
    const search = {
      pageNumber: pageNumber.toString(),
      pageSize: TAG_PAGE_SIZE.toString()
    };
 
    return apiService.get(`/trigger/paged/0/${search.pageSize}`);
  };
 
  const {
    data: response,
    isError,
    isLoading,
    isSuccess,
    isFetching,
    isFetchingNextPage,
    fetchNextPage,
    hasNextPage,
    refetch,
    ...rest
  } = useInfiniteQuery(query, ({ pageParam = 1 }) => fetchTriggers(pageParam), {
    getNextPageParam: (lastPage, pages) => {
      const totalPages = lastPage.data.totalPages || 1;
      return totalPages === pages.length ? undefined : pages.length + 1;
    }
  });
 
  const data = useMemo(
    () => response?.pages.map((page) => page.data.content).flat() || [],
    [response?.pages]
  );
 
  return {
    data,
    isError,
    isLoading,
    isSuccess,
    isFetching,
    isFetchingNextPage,
    fetchNextPage,
    hasNextPage,
    refetch,
    ...rest
  };
};
 
export default useGetTriggers;

Upvotes: 2

Views: 5947

Answers (1)

ThanosDi
ThanosDi

Reputation: 339

You can use the onSuccess method of react-query (https://react-query.tanstack.com/reference/useMutation)

onSuccess: (data: TData, variables: TVariables, context?: TContext) => Promise | void Optional
This function will fire when the mutation is successful and will be passed the mutation's result. If a promise is returned, it will be awaited and resolved before proceeding

const { mutate, isLoading, error, isSuccess } = useMutation(
    (formData: ICalculationEngine['TriggerDailyOpt1']) =>
        apiService.post('/trigger/DailyOpt1', formData),
    {
        mutationKey: 'DailyOpt1',
        onSuccess: (_, { variables }) => {
            // Execute your query as you see fit.
            apiService.get(...);
        },
    }
);

As a best practice thought I would suggest the POST request to return the updated data if possible to avoid this exact need.

Upvotes: 1

Related Questions