skip to Main Content

I have this custom hook that used to fetch multiple requests

import dashboardApi from '@api/dashboardApi'
import { queryKeys } from '@constants/queryKeys'
import { TOP_PROJECT_SORT } from '@models/projectCost'
import { UseQueryOptions, UseQueryResult, useQuery } from '@tanstack/react-query'
import { NotifyService } from '@utils/notify'
import { AxiosError } from 'axios'

function useGetExportPDFData(
  queryOptions?: UseQueryOptions<any, any, any, any>,
): UseQueryResult<any, any> {
  // if top member mode is custom time range, then don't pass query and cal API of previous data
  const requests = [
    dashboardApi.getTopProjects({
      sortBy: TOP_PROJECT_SORT.AverageCost,
      order: 'desc',
      limit: '6',
    }),
  ]

  return useQuery(
    [queryKeys.account],
    async () => {
      return await Promise.all(requests)
    },
    {
      enabled: false,
      onError: (error: AxiosError) => {
        NotifyService.error(error)
      },
      ...queryOptions,
    },
  )
}

export default useGetExportPDFData

The problem is whenever the 2 jotai state changes (topMemberTimeRange and customDateRange), it also refetch again, although I did set enable to false, I only want to trigger this when refetch is called. How to do that?

import MainPageLayout from '@components/layout/MainPageLayout'
import PersonalRevenueHeader from '@features/personal-revenue/components/PersonalRevenueHeader'
import { TopMemberMode } from '@features/personal-revenue/constant'
import useGetExportPDFData from '@features/personal-revenue/hooks/useGetExportPDFData'
import { RevenuetMember, TableRevenueMember, TopMemberResponse } from '@models/personalRevenue'
import { calculatePercentageChange } from '@utils/common'
import { useAtom } from 'jotai'
import _ from 'lodash'
import { Outlet } from 'react-router-dom'
import pdf from './pdf'
import { customTimeRange, topMemberTimeRangeQuery } from './store'

function PersonalRevenue() {
  const [topMemberTimeRange] = useAtom(topMemberTimeRangeQuery)
  const [customDateRange] = useAtom(customTimeRange)
  const { refetch } = useGetExportPDFData({
    enabled: false,
    refetchOnWindowFocus: false,
    refetchOnMount: false,
  })
  return (
    <MainPageLayout
      title="PERSONAL REVENUE"
      header={<PersonalRevenueHeader exportData={exportPDF} />}
    >
      <Outlet />
    </MainPageLayout>
  )
}

3

Answers


  1. const requests = [
      dashboardApi.getTopProjects({
        sortBy: TOP_PROJECT_SORT.AverageCost,
        order: 'desc',
        limit: '6',
      }),
    ]
    

    This code is in the body of the hook, which means it will execute on every render. So every time your component renders, you call getTopProjects(/*...*/). This happens no matter whether the query is enabled, since this code is unrelated to the query.

    If you only want this code to execute when fetching the query, then move it into the query function:

    return useQuery(
      [queryKeys.account],
      async () => {
        const requests = [
          dashboardApi.getTopProjects({
            sortBy: TOP_PROJECT_SORT.AverageCost,
            order: "desc",
            limit: "6",
          }),
        ];
        return await Promise.all(requests);
      },
      {
        enabled: false,
        onError: (error: AxiosError) => {
          NotifyService.error(error);
        },
        ...queryOptions,
      },
    );
    
    
    Login or Signup to reply.
  2. You can set the options

    {
      ...,
      staleTime: Infinity
      cacheTime: Infinity,
      ...
    }
    

    This options will prevent useQuery from refetching.

    Login or Signup to reply.
  3. It’s not "useQuery" that makes the request, but this part

     const requests = [
        dashboardApi.getTopProjects({
          sortBy: TOP_PROJECT_SORT.AverageCost,
          order: 'desc',
          limit: '6',
        }),
      ]
    

    every time your states "topMemberTimeRange", "customDateRange" changes it calls const { refetch } = useGetExportPDFData({ enabled: false, refetchOnWindowFocus: false, refetchOnMount: false, })
    and creates a new array "requests" where you make a request.
    you can pass it as a second parameter

    return useQuery(
    [queryKeys.account],
    async () => {
      return dashboardApi.getTopProjects({
      sortBy: TOP_PROJECT_SORT.AverageCost,
      order: 'desc',
      limit: '6',
    })
    },
    {
      enabled: false,
      onError: (error: AxiosError) => {
        NotifyService.error(error)
      },
      ...queryOptions,
    },
    

    )

    or if you wont array of promises
    PS: Nicholas Tower made example with array of promises more clear

    useQuery(
    [queryKeys.account],
    async () => {
      return Promise.all([dashboardApi.getTopProjects({
      sortBy: TOP_PROJECT_SORT.AverageCost,
      order: 'desc',
      limit: '6',
    })])
    },
    {
      enabled: false,
      onError: (error: AxiosError) => {
        NotifyService.error(error)
      },
      ...queryOptions,
    },
    

    )

    but it looks weird

    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search