query: useInfiniteQuery is fetching twice the first page

Hi,

I’ve been reading the doc and trying to figure out what I’m doing wrong but.

I have this code

  const { status, data, error, isFetching, isFetchingMore, fetchMore, canFetchMore } = useInfiniteQuery(
    "activities",
    async (_key: any, nextPage = 1) => {
      return eventsServices.getActivities({ ...selectedParams, page: nextPage, perPage: 30 });
    },
    {
      getFetchMore: (lastGroup: IActivity[], groups: IActivity[][]) => {
        return lastGroup?.length ? groups.length : false;
      }
    }
  );

The firs time the page loads it will fetch my activities from page one, then when I scroll and fetchMore it’s called, it’s still fetching the first page. According to the docs, there should be a nextCursor property in lastGroup but either the docs aren’t up to date or I’m doing something wrong because I’m getting an undefined.

Also, according to the docs, By default, the info returned from getFetchMore will be supplied to the query function. So I’m wondering if there’s something I’m doing wrong but it should be pretty straight forward according to the docs.

Any help would be greatly appreciated.

About this issue

  • Original URL
  • State: closed
  • Created 4 years ago
  • Reactions: 3
  • Comments: 37 (5 by maintainers)

Most upvoted comments

Thank you very much for the help, really appreciated guys. I’ve solved the problem by completely uninstalling react-query.

In “dev mode” each component gets mounted twice, it’s a side effect of reacts strict mode. This will not happen once build. https://reactjs.org/docs/strict-mode.html

Are you using React 18 and Strict Mode? If yes, this is the problem. It’s a “feature” included in React 18 to test that your component can be un-mounted and mounted again, in preparation for a future React feature. It’s enabled only when in Strick Mode. So either take Strick Mode out or work around it similar to what the blog here describes.

Here it’s explained with a solution: https://blog.ag-grid.com/avoiding-react-18-double-mount/

I’m sorry to see you go! Its a shame you weren’t able to wait just a day or two longer when I regularly plan on reviewing, answering, and fixing issues just like this one. Of course, if you truly need same day turnaround on issues, you’re more than welcome to sign up for my diamond sponsorship plan!

Now i would either add code to the working example until it looks like your code, or work from your code backwards until it looks like the example.

Could it be that the second request you are seeing is just because of refetchOnWindowFocus, because that happens a lot…

Hi!

I am having a similar issue. When fetching the initial first page of the infinite paginated request, it will fetch the page twice.

image

Here is the code for the useInfiniteQuery:

export const useAudiosInfiniteQuery = (options: useAudiosInfiniteOptions = { type: 'audios' }) => {
  const key = generateUseAudiosKey(options);
  const fetchAudios = async (params?: Record<string, any>, page: number = 1) => {
    console.log(page)
    const qs = `?page=${page}&${queryString.stringify(params)}`
    const { data } = await request<AudioListItem[]>(key + qs);
    return data;
  }
  const params = {...options.params, size: options.size = 15 };
  return useInfiniteQuery<AudioListItem[], ErrorResponse>([key, params], ({ pageParam = 1 }) => 
    fetchAudios(params, pageParam), {
      getNextPageParam: (lastPage, allPages) => {
        return lastPage.length > 0 ? allPages.length + 1 : undefined
      },
    });
}

Sorry if this is considered necro-posting…

@tannerlinsley hey 😃

Any luck solving this? I’m seeing it also. Promise to not give up on the library, I hate apollo with a passion 🗡️

I’m sure it wasn’t triggered because focus back, I put the refetchOnWindowFocus: false. Or am I still missing something?

Thanks!

sorry, I’m not sure how I’ve missed this.

seems to be an issue with the implementation of useIntersectionObserver. I can see that onIntersect is called twice, not sure why. adding a check solves it:

  useIntersectionObserver({
    target: loadMoreButtonRef,
    onIntersect: () => {
      if (!isFetchingNextPage) {
        fetchNextPage();
      }
    },
    enabled: !!hasNextPage
  });

Personally, I’ve been using useInView from react-intersection-observer with great success in our products.

In case of the component being remounted, do not forget to use the signal from the context to implement some kind of query canceling. After updating to React 18 and using Strict mode, a lot of components started to re-mount after being mounted first (React 18 migration guide). I use Axios in my project and by default, every query was fired two times. However using the signal and converting it to axios’s CancelToken the first one is immediately cancelled and only the second one is being executed.

export default class AxiosCancelTokenHelper {
    public static cancelTokenFrom = (signal: AbortSignal | undefined): {cancelToken: CancelToken} => {
        const source = axios.CancelToken.source()
        // Cancel the request if React Query signals to abort
        signal?.addEventListener('abort', () => {
            source.cancel('Query cancelled by React query.')
        })
        return {cancelToken: source.token}
    }
}
....
useInfiniteQuery(..., (context) => {
   axios...(..., AxiosCancelTokenHelper.cancelTokenFrom(context.signal)   ) // or just use the source.token with the other options you have
}, {
    refetchOnWindowFocus: false,
....
})

refetchOnWindowFocus: false helped me. thanks @TkDodo

refetchOnWindowFocus should be false by default - double request is not intuitive at all and if it goes double then one of the requests is obsolete and useless in best case scenario, in worst case scenario might cause unwanted side-effects.

@TkDodo The issue was because of my routing, the route was mounting the component twice this is why I had the issue. it was not related to react-query, thank you anyway 🙏