Infinite scroll updates data twice

Viewed 359

I have a lazy loaded table (infinite scroll). Unfortunatelly, I don't know why but it updates on data twice when I scroll to the bottom. So two queries to graphql are made instead of one. If I remove data from fetchMore dependency it works fine (but then, eslint throws warning so it is not a solution). Also when I remove scroll and replace it by manual button and click for fetch also works good, so I dont know if problem is in query or maybe in WithInfiniteScroll

const LIMIT = 10;

const updateQuery = (
  previousQueryResult: GetStaffQuery,
  options: {
    fetchMoreResult?: GetStaffQuery;
    variables?: GetStaffQueryVariables;
  }
): GetStaffQuery => {
  const {fetchMoreResult} = options;
  const currentNodes = previousQueryResult.staff.nodes || [];
  const newNodes = fetchMoreResult?.staff.nodes || [];
  const newResult = {
    staff: {
      ...fetchMoreResult?.staff,
      nodes: [...currentNodes, ...newNodes],
    },
  };

  return newResult;
};

export const useUsersList = () => {
  const [isInitialFetching, setIsInitialFetching] = useState(true);

  const {data, fetchMore: handleFetchMore, loading} = useGetStaffQuery({
    variables: {limit: LIMIT, nextToken: null},
    onCompleted: () => {
      setIsInitialFetching(false);
    },
  });

  useEffect(() => {
    debugger; //triggered twice when scrolled to the bottom
  }, [data]);

  const fetchMore = useCallback(() => {
    const nextToken = data?.staff.nextToken || null;

    if (nextToken && !loading && !isInitialFetching) {
      const queryVariables: GetStaffQueryVariables = {
        limit: LIMIT,
        nextToken,
      };
      handleFetchMore({variables: queryVariables, updateQuery});
    }
  }, [data, handleFetchMore, isInitialFetching, loading]);

  return {
    isLoading: loading,
    canLoadMore: Boolean(data?.staff.nextToken && !loading) || false,
    fetchMore,
    users: data?.staff.nodes || [],
  };
};

Infinite scroll:

import React, {useEffect, ReactNode} from 'react';
import {useInView} from 'react-intersection-observer';

type PropTypes = {
  children?: ReactNode;
  canLoadMore: boolean;
  onLoadMore: () => unknown;
};

const rootMargin = '400px';

export const WithInfiniteScroll = ({
  children,
  canLoadMore,
  onLoadMore,
}: PropTypes) => {
  const [ref, isElementInViewport] = useInView({
    rootMargin,
    skip: !canLoadMore,
  });

  useEffect(() => {
    if (canLoadMore && isElementInViewport) {
      onLoadMore();
    }
  }, [canLoadMore, isElementInViewport, onLoadMore]);

  return (
    <>
      {children}
      <div ref={ref} />
    </>
  );
};

and some draft of component:

  <WithInfiniteScroll canLoadMore={canLoadMore} onLoadMore={onLoadMore}>
    <div>
       {users.map(user => <span>{user.id}</span>)}
    </div>
</WithInfiniteScroll>
0 Answers
Related