onderonur / react-infinite-scroll-hook

React hook for creating infinite scroll components.
https://onderonur.github.io/react-infinite-scroll-hook/
MIT License
453 stars 37 forks source link

Infinite loop with Reversed Vertical list #36

Open Aniket-IN opened 1 year ago

Aniket-IN commented 1 year ago

Hi,

First of all thank you so much for the amazing package, I'm trying to implement it with react-query for a chat application.

Basically, we need to first load most recent messages and when user scrolls to the top of the container, we load old messages. Just like whatsapp.

I got the load on scroll working and everything is fine.

Just having one small issue: What happens is on the Initial data load by react-query the container's scroll position is at the top. And our sentryRef element is also on the top, that triggers loadMore and after loading more still the scroll position stays at top and it just keeps loading more and more, until all the data is loaded.

could you please provide a solution to this problem 😢.

Thank you.

Here's the code:

const ChatBox = ({ thread }: ChatBoxProps) => {
  const { axios } = useAxios();

  const fetchMessages = async ({ pageParam = 0 }) => {
    const response = await axios.get(
      `/api/v1/message-threads/${thread.id}/messages`,
      {
        params: {
          page_size: 10,
          pagination_mode: "cursor",
          cursor: pageParam,
          sort_field: "created_at",
          sort_direction: "desc",
        },
      }
    );

    return response.data;
  };

  const {
    isSuccess,
    data,
    isFetching,
    isFetchingNextPage,
    fetchNextPage,
    hasNextPage,
    isError,
  } = useInfiniteQuery<MessagesResponse>({
    queryKey: ["messages"],
    queryFn: fetchMessages,
    select: (data) => {
      return {
        pages: [...data.pages].reverse(),
        pageParams: [...data.pageParams].reverse(),
      };
    },
    getNextPageParam: (lastPage, pages) => lastPage.next_cursor,
  });

  const [sentryRef, { rootRef }] = useInfiniteScroll({
    loading: isFetching,
    hasNextPage: !!hasNextPage,
    onLoadMore: () => fetchNextPage(),
    disabled: isError,
    rootMargin: "0px 0px 0px 0px",
  });

  return (
    <div className="flex flex-grow flex-col divide-y border-b bg-white">
      <ChatHeader thread={thread} />

      {/* Chat Messages */}
      <div
        ref={rootRef}
        className="bg-accent h-0 flex-auto flex-col space-y-3 overflow-auto px-4"
      >
        {isSuccess && (isFetchingNextPage || hasNextPage) && (
          <div ref={sentryRef} className="py-3 text-center text-slate-500">
            Loading old chats...
          </div>
        )}

        {data?.pages.map((group, i) => (
          <Fragment key={i}>
            {[...group.data].reverse().map((message) => (
              <MessageBubble
                key={message.id}
                message={message}
                direction={
                  thread.contact_phone_number == message.from
                    ? "inbound"
                    : "outbound"
                }
              />
            ))}
          </Fragment>
        ))}
      </div>

      <MessageSender />
    </div>
  );
};
onderonur commented 1 year ago

Hello there 👋

Thanks for your intereset to this package and also for this issue 🙏

If I understood the problem correctly, you need to handle the scroll position.

If you go to the demo and select Reversed Vertically Scrollable List for "List Type", you can see the behavior is similar to what would be expected from a chat.

The code for that component is here.

Basically, you need an useEffect which will update the scroll position after the new items are loaded and an onScroll handler to keep track of the current scroll position. And don't forget to set both scrollableRootRef and infiniteRef by using a useCallback (like here) to prevent any performance issues.

I think you will get it when you see the code 😄

And I see that these examples are a little scattered all around and people may miss them. So I'm planning to add these to the README.md or update the demo site to be more explicit.

I hope this helps you to solve the problem. If you have any further questions or if this answer solves the problem, please comment 🙏

I'll keep this issue open until I improve the documentation of these examples.

Thanks 🎉

SeanRoberts commented 2 months ago

For anyone finding this the layout of the repo has changed and the updated link to the example code is here: https://github.com/onderonur/react-infinite-scroll-hook/blob/main/apps/demo/src/components/infinite-list-with-reverse-vertical-scroll.tsx