Skip to content

[Question] I have a bunch of use cases together that I want to implement -> grid inside a dialog + infinite scroll + filters #187

@adi-coreflow

Description

@adi-coreflow

Hey @jaredLunde

There's a bunch of things I'm trying to do together:
Now if I add allMedia to usePositioner deps, because of the Infinite scroll, the grid starts glitching,

I also wanted to have loaders at the end as shown in the itemsWithPlaceholders, now if i switch the tabs and the data changes it errors out and if i put allMedia in the deps, it keeps glitching

Also one issue related to the grid rendering, whenever i render it for the first time the height and width are 0 and then if I change the filter it renders!

Would appreciate a lot if you can help me out with this thanks!

For reference this is my code:

import {
  useInfiniteLoader,
  useMasonry,
  usePositioner,
  useResizeObserver,
} from 'masonic';
import { SkeletonTile } from './components/Skeleton';
import { useScroller, useSize } from 'mini-virtual-list';

export const LOADER_ID_PREFIX = '__skeleton__';
export const GUTTER_SIZE = 3;

type GridProps<T> = {
  allMedia: T[];
  renderItem: (mediaItem: T) => React.ReactNode;
  maxColumnCount?: number;
  loaderGridSize?: number;
  isLoading?: boolean;
  isFetchingMore?: boolean;
  hasMore?: boolean;
  resetGrid?: boolean;
  onLoadMore?: () => Promise<any>;
  // Pass in a ref function to get the scroll container element
  scrollContainer: MutableRefObject<HTMLElement | null>;
};

const Grid = <T,>({
  allMedia = [],
  renderItem,
  maxColumnCount = 5,
  loaderGridSize = 9,
  isLoading = false,
  isFetchingMore = false,
  hasMore = false,
  onLoadMore,
  scrollContainer,
}:  GridProps<T>) => {
  const { scrollTop, isScrolling } = useScroller(scrollContainer);
  const { width, height } = useSize(scrollContainer);

  const positioner = usePositioner(
    {
      width,
      columnGutter: GUTTER_SIZE,
      rowGutter: GUTTER_SIZE,
      maxColumnCount,
    },
    [],
  );

  const resizeObserver = useResizeObserver(positioner);
 
  const itemsWithPlaceholders = useMemo(() => {
    if (!isFetchingMore && !isLoading) return allMedia;
     return [...allMedia, ...getPlaceHolderItems<T>(loaderGridSize)];
  }, [allMedia, isFetchingMore, isLoading, loaderGridSize]);

  const loadMoreItems = useCallback(async () => {
    if (!hasMore || !onLoadMore || isFetchingMore) return;
    await onLoadMore();
  }, [hasMore, onLoadMore, isFetchingMore]);

  const isItemLoaded = useCallback(
    (idx: number) => idx < allMedia.length,
    [allMedia.length],
  );

  const maybeLoadMore = useInfiniteLoader(loadMoreItems, {
    isItemLoaded,
    threshold: Math.max(6, loaderGridSize),
  });

  const itemKey = useCallback((data: any, index: number) => {
    return data?.id ?? `item-${index}`;
  }, []);

  const renderItems = useCallback(
    ({ data }: { data: T }) => {
      if ((data as any)?.id?.startsWith(LOADER_ID_PREFIX)) {
        return <SkeletonTile />;
      }
      return renderItem(data);
    },
    [renderItem],
  );

  return useMasonry({
    id: 'dream-masonry-grid',
    positioner,
    resizeObserver,
    items: itemsWithPlaceholders,
    height,
    scrollTop,
    isScrolling,
    overscanBy: 2,
    itemKey,
    itemHeightEstimate: 300,
    render: renderItems,
    onRender: maybeLoadMore,
  });
};

export default DreamGrid;

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions