Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

InfiniteLoader not working when api data fetch limit is equal to columnCount in FixedSizeGrid. #764

Open
ayushbharadva25 opened this issue Jun 3, 2024 · 0 comments

Comments

@ayushbharadva25
Copy link

ayushbharadva25 commented Jun 3, 2024

Hi @bvaughn, I am using react-window-infinite-loader along with FixedSizeGrid it is working properly, except in the scenario where the limit of data in API call is equal to column count. I am trying to find the reason but couldn't found yet. If anyone knows the reason then help..

Below is the code snippets:

  1. VirtualizedInfiniteList Component :
import { PropTypes } from 'prop-types';
import { FixedSizeGrid, areEqual } from 'react-window';
import InfiniteLoader from 'react-window-infinite-loader';
import AutoSizer from 'react-virtualized-auto-sizer';
import './store_projects.scss';
import { StoreMediaQueries } from '../../constants';
import useMediaQuery from '../../hooks/useMediaQuery';

const { mediaQueries } = StoreMediaQueries;

const getIndexFromGridPosition = (col, row, columnCount) => (row * columnCount) + col;

const GridCell = memo(({
  data: { items, gridColumnCount, children }, columnIndex, rowIndex, style,
}) => {
  const index = getIndexFromGridPosition(columnIndex, rowIndex, gridColumnCount);

  if (!items || items.length === 0 || index >= items.length) {
    return null;
  }

  return (
    <div className="store-project-card-wrapper" style={style}>
      {children(items[index])}
    </div>
  );
}, areEqual);

const VirtualizedInfiniteList = memo(({
  items,
  hasMore,
  loadMoreItems,
  threshold,
  children,
}) => {
  const activeMediaQuery = useMediaQuery(mediaQueries);
  const { gridColumnCount = 1, gridRowHeight } = activeMediaQuery?.mediaQuery ?? {};

  const itemCount = useMemo(() => (hasMore ? items.length + 1 : items.length), [hasMore, items.length]);

  const isItemLoaded = (index) => !hasMore || index < items.length;

  const handleItemsRender = useCallback(({
    visibleRowStartIndex, visibleRowStopIndex, visibleColumnStopIndex, onItemsRendered,
  }) => {
    console.log('visibleRowStartIndex :', visibleRowStartIndex, '\nvisibleRowStopIndex :', visibleRowStopIndex, '\nvisibleColumnStopIndex :', visibleColumnStopIndex);

    console.log('visibleStartIndex :', visibleRowStartIndex * (visibleColumnStopIndex + 1), '\nvisibleStopIndex :', visibleRowStopIndex * (visibleColumnStopIndex + 1));
    onItemsRendered({
      visibleStartIndex: visibleRowStartIndex * (visibleColumnStopIndex + 1),
      visibleStopIndex: visibleRowStopIndex * (visibleColumnStopIndex + 1),
    });
  }, []);

  return (
    <AutoSizer>
      {({ height, width }) => (
        <InfiniteLoader
          isItemLoaded={isItemLoaded}
          itemCount={itemCount}
          loadMoreItems={loadMoreItems}
          threshold={threshold}
        >
          {({ onItemsRendered, ref }) => (
            <FixedSizeGrid
              className="virtualized-grid-wrapper"
              columnCount={gridColumnCount}
              columnWidth={width / gridColumnCount}
              height={height}
              itemData={{ items, gridColumnCount, children }}
              ref={ref}
              rowCount={Math.ceil(items.length / gridColumnCount)}
              rowHeight={gridRowHeight}
              width={width}
              onItemsRendered={(props) => handleItemsRender({ ...props, onItemsRendered })}
            >
              {GridCell}
            </FixedSizeGrid>
          )}
        </InfiniteLoader>
      )}
    </AutoSizer>
  );
});

VirtualizedInfiniteList.propTypes = {
  items: PropTypes.shape([]).isRequired,
  hasMore: PropTypes.bool,
  loadMoreItems: PropTypes.func,
  threshold: PropTypes.number,
  children: PropTypes.func.isRequired,
};

VirtualizedInfiniteList.defaultProps = {
  hasMore: false,
  loadMoreItems: () => {},
  threshold: 5,
};

GridCell.propTypes = {
  data: PropTypes.shape({
    items: PropTypes.shape([]),
    gridColumnCount: PropTypes.number,
    children: PropTypes.func,
  }).isRequired,
  columnIndex: PropTypes.number.isRequired,
  rowIndex: PropTypes.number.isRequired,
  style: PropTypes.shape({}).isRequired,
};

export default VirtualizedInfiniteList;
  1. loadMoreItems function :
  const [getStoreProjects, {
    fetchMore,
  }] = useLazyQuery(getProjects, {
    variables: { limit: allProjectsLimit, offset: 0 },
    onCompleted: (res) => {
      const { filterProjectsForAdmin } = res ?? {};
      const projects = filterProjectsForAdmin.length ? filterProjectsForAdmin : [];
      const hasMoreProjects = filterProjectsForAdmin.length >= allProjectsLimit;

      setProject(() => ({
        list: projects,
        hasMore: hasMoreProjects,
        isLoading: false,
      }));
    },
    onError: (error) => {
      showToast({ description: error.message, title: 'Error', type: 'error' });
      setProject(() => ({
        list: [],
        hasMore: false,
        isLoading: false,
      }));
    },
    fetchPolicy: 'network-only',
  });
  
    const loadMoreItems = useCallback(() => {
    if (!isLoading && hasMore) {
      setProject((prev) => ({ ...prev, isLoading: true }));
      fetchMore({
        variables: {
          limit: allProjectsLimit,
          offset: list.length,
        },
        updateQuery: (prev, { fetchMoreResult: { filterProjectsForAdmin: storeProjects } }) => {
          if (!storeProjects.length) {
            return prev;
          }

          setProject((prevProjects) => ({
            list: [...prevProjects.list, ...storeProjects],
            hasMore: storeProjects.length >= allProjectsLimit,
            isLoading: false,
          }));
          return null;
        },
      });
    }
  }, [fetchMore, hasMore, isLoading, list.length]);

here, the issue occurs when the value of allProjectsLimit and gridColumnCount both have same value. the issue is described below with example.

issue : I am fetching data from an API, it's an infinite scroll api so I need to pass limit in every api call. now for example, suppose there are 20 data items. and the limit of data items in a single API call is 5. and gridColumnCount is also 5

• ideal behaviour : there should be 5 API calls and all the data items should be displayed.
• current behaviour : only one api call is made and only 5 data items are displayed. there is no further loadMoreItems call.

Any help regarding above issue would be appreciated, Thanks.

@ayushbharadva25 ayushbharadva25 changed the title InfiniteLoader not working properly when the fetch limit is less than 5. Jun 4, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
1 participant