【问题标题】:How to avoid scrollbar staying on top when loading more data (infinite scroll) in React在 React 中加载更多数据(无限滚动)时如何避免滚动条停留在顶部
【发布时间】:2022-11-18 11:38:06
【问题描述】:

我正在无限向上滚动聊天室,判断看到最后一条消息并加载数据,但是滚动条仍然在页面顶部,你知道的,它会自动无限执行调用api,如何保持该位置上一条消息的滚动条

【问题讨论】:

    标签: javascript html css reactjs infinite-scroll


    【解决方案1】:

    如果您有添加的新元素的引用,您可以使用 element.scrollIntoView() 来确保它在渲染后可见。

    https://developer.mozilla.org/en-US/docs/Web/API/Element/scrollIntoView

    但: 在聊天室中,这可能并不总是正确的做法,因为用户可能已经向上滚动以复制/粘贴某些内容,而失去位置会很烦人。因此,在通过 JS 滚动之前,请检查聊天是否已经在底部。

    您可以查看 twitch-chat 的工作原理以获得一个很好的示例。如果有新的聊天消息,用户会收到一条信息。

    【讨论】:

    • 谢谢你的回答,但是我遇到的问题是加载历史信息,滚动条一直停留在最上面,导致我加载更多的历史信息毫无节制
    • 啊不好意思,那我误会了。处理此问题的一种方法是:执行数据获取 -> 阻止 JS 进行任何新的获取 -> 获取对“旧”最顶层聊天消息的引用 -> 插入新内容 -> 滚动回旧的最顶层聊天消息 -> 重新启用滚动获取
    【解决方案2】:

    此解决方案适用于图书馆 https://github.com/ankeetmaini/react-infinite-scroll-component

    我使用的结构基于传递给子组件的道具。父组件负责获取和控制状态。

    父组件:

    const fetchScrollData = () => {
        // Here we set that we are not able to do scrolling fetching
        setIsLoadingScrollData(true);
        // Apply here some pagination calculation
        searchData()
            .then((tempData) => {
             // Here i am saving the id of the first message
             // I had before scrolling
              setShouldScrollToId(data[0].id);
              const newData = tempData.concat(data);
              setData(newData);
              // Apply here some logic, depending if you have finished or not
              setHasMoreData(true);
            })
            .then(() => {
              setTimeout(() => {
                // Change the timeout accordingly
                // hack for setting the isloading to false when everything is done
                setIsLoadingScrollData(false);
              }, 1500);
            });
      };
    

    子组件

    type PropsType = {
      fetchScrollData: () => void;
      hasMoreData: boolean;
      data: string[];
      isLoadingScrollData: boolean;
      shouldScrollToId: string;
    };
    
    const ChildComponent: FC<PropsType> = (props: PropsType) => {
      useEffect(() => {
        if (props.shouldScrollToId !== '') {
          const element = document.getElementById(props.shouldScrollToId);
          if (element) {
            element.scrollIntoView({ behavior: 'smooth' });
          }
        }
      });
      ....
      return (
       <div
          className="message-list overflow-scroll"
          id="scrollableDiv"
          style={{
            display: 'flex',
            flexDirection: 'column-reverse'
          }}>
          <InfiniteScroll
              dataLength={props.data.length}
              hasMore={props.hasMoreData && !props.isLoadingScrollData}
              inverse={true}
              next={props.fetchScrollData}
              scrollableTarget="scrollableDiv"
              style={{ display: 'flex', flexDirection: 'column-reverse', perspective: '1px' }}
              loader={<></>}>
              <div>
               {props.data.map((d, index) => {
                // Here i am setting the id which the useEffect will use to do the scroll
                <div key={index} id={d.id} >div - #{message}</div>;
               })}
             </div>
            {props.isLoadingScrollData ? <Spinner></Spinner> : null}
          </InfiniteScroll>
        </div>
    

    我在加载器上遇到了一些问题,所以我决定不使用它。相反,我创建了自己的 Spinner 组件,并根据显示我们是否仍在从滚动中获取数据的道具使其出现或消失。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2016-07-04
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2018-03-26
      相关资源
      最近更新 更多