Skip to content

Commit

Permalink
fix: move scroll by scrollEvent and separate it as hook
Browse files Browse the repository at this point in the history
  • Loading branch information
HoonBaek committed Mar 31, 2023
1 parent e114481 commit a2f207d
Show file tree
Hide file tree
Showing 2 changed files with 53 additions and 43 deletions.
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import './openchannel-message-list.scss';

import React, { ReactElement, useRef, useState, useMemo, useLayoutEffect, useEffect } from 'react';
import React, { ReactElement, useRef, useState, useMemo } from 'react';
import { FileMessage, UserMessage } from '@sendbird/chat/message';
import isSameDay from 'date-fns/isSameDay';

Expand All @@ -11,7 +11,7 @@ import { compareMessagesForGrouping } from '../../context/utils';
import { useOpenChannelContext } from '../../context/OpenChannelProvider';
import OpenChannelMessage from '../OpenChannelMessage';
import { RenderMessageProps } from '../../../../types';
import { SCROLL_BUFFER } from '../../../../utils/consts';
import { useHandleOnScrollCallback } from './useHandleOnScrollCallback';

export type OpenchannelMessageListProps = {
renderMessage?: (props: RenderMessageProps) => React.ElementType<RenderMessageProps>;
Expand All @@ -31,54 +31,19 @@ function OpenchannelMessageList(
const scrollRef = ref || useRef(null);
const [showScrollDownButton, setShowScrollDownButton] = useState(false);

// page scroll states
const [pageScrollHeight, setPageScrollHeight] = useState(0);
const [pageScrollTop, setPageScrollTop] = useState(0);

const handleOnScroll = (e) => {
const element = e.target;
const {
scrollTop,
scrollHeight,
clientHeight,
} = element;
if (scrollTop !== pageScrollTop) {
setPageScrollTop(scrollTop);
}
if (scrollHeight > scrollTop + clientHeight + 1) {
setShowScrollDownButton(true);
} else {
setShowScrollDownButton(false);
}

if (!hasMore) {
return;
}
if (scrollTop < SCROLL_BUFFER) {
onScroll(() => {
// noop
});
}
};

const scrollToBottom = () => {
if (scrollRef && scrollRef.current) {
scrollRef.current.scrollTo(0, scrollRef.current.scrollHeight);
setShowScrollDownButton(false);
}
};

useEffect(() => {
setPageScrollHeight(scrollRef?.current?.scrollHeight || 0);
}, [scrollRef?.current?.scrollHeight]);
useLayoutEffect(() => {
/**
* The pageScrollHeight and pageScrollTop have different values
* with the scrollHeight and scrollTop of srollRef.current at this moment
*/
const previousScrollBottom = pageScrollHeight - pageScrollTop;
scrollRef.current.scrollTop = scrollRef.current.scrollHeight - previousScrollBottom;
}, [allMessages?.length]);
const handleOnScroll = useHandleOnScrollCallback({
setShowScrollDownButton,
hasMore,
onScroll,
scrollRef,
});

const memoizedMessageList = useMemo(() => {
if (allMessages.length > 0) {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
import React, { useCallback } from "react";
import { SCROLL_BUFFER } from "../../../../utils/consts";

export interface UseHandleOnScrollCallbackProps {
setShowScrollDownButton: React.Dispatch<React.SetStateAction<boolean>>;
hasMore: boolean;
onScroll(fn: () => void): void;
scrollRef: React.RefObject<HTMLDivElement>;
}

export function useHandleOnScrollCallback({
setShowScrollDownButton,
hasMore,
onScroll,
scrollRef,
}: UseHandleOnScrollCallbackProps): (e: React.UIEvent<HTMLElement>) => void {
return useCallback((e) => {
const element = e.target as Element;
const {
scrollTop,
scrollHeight,
clientHeight,
} = element;
const scrollBottom = scrollHeight - scrollTop;
if (scrollHeight > scrollTop + clientHeight + 1) {
setShowScrollDownButton(true);
} else {
setShowScrollDownButton(false);
}
if (!hasMore) {
return;
}
if (scrollTop < SCROLL_BUFFER) {
onScroll(() => {
// Fetch more messages
scrollRef.current.scrollTop = scrollRef.current.scrollHeight - scrollBottom;
});
}
}, [
setShowScrollDownButton,
hasMore,
onScroll,
scrollRef,
]);
}

0 comments on commit a2f207d

Please sign in to comment.