[React] 上拉加载更多

avatarplhDigital nomad

https://user-images.githubusercontent.com/14355994/233860778-e1aad3f3-2b30-493d-8c23-61b85b2b3d79.mov

这样处理的原因是因为, 当你滑到最顶部再 push 元素, 会直接定位到顶部, 需要scrollIntoView 到之前的位置.

export function ContentComponent() {
  const scrollEl = useRef<HTMLDivElement>(null);
  const [distanceToBottom, setDistanceToBottom] = useState<number | null>(null);
  // handle scroll event function, when scroll trigger it.
  const handleScroll = async () => {
    // when distance to top less than 300px
    if (
      message.length > 0 &&
      Number(scrollEl.current?.scrollTop) < 300 &&
      !loadingMessage &&
      hasMessage
    ) {
      // request API first
      const { payload } = await asyncLoadMessage();
      const distanceToTop = getTopSpace();
      dispatch(asyncLoadMessage(payload));
      // only when current position to top is 0px, need to reset scroll position
      if (Number(distanceToTop) === 0) {
        setDistanceToBottom(getBottomSpace());
      }
    }
  };

  useLayoutEffect(() => {
    if (
      scrollEl.current?.scrollTop !== undefined &&
      distanceToBottom !== null
    ) {
      scrollEl.current.scrollTop =
        scrollEl.current.scrollHeight - distanceToBottom;
      setDistanceToBottom(null);
    }
  }, [distanceToBottom]);

  return (
    <div
      className="overflow-y-auto flex-1 relative px-3.5 py-0"
      ref={scrollEl}
      onScroll={throttle(handleScroll)}
    >
      <TipComponent />
      {message.map((msg) => (
        <MessageComponent key={msg._id} data={msg} />
      ))}
    </div>
  )
}