You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

NextJS中自定义useScrollPosition Hook失效,无法触发下一页数据获取

解决方案

你的自定义useScrollPosition Hook失效的核心原因是监听了错误的滚动容器:你监听的是window的scroll事件,但实际页面中滚动的是Feed组件所在的<div className="h-full">容器(而非整个窗口),导致window的滚动事件从未触发,scrollPosition自然不会更新。

同时,原Hook中未缓存handleScroll函数,在组件重渲染时可能出现事件监听的清理/绑定不一致问题,需要用useCallback优化。

步骤1:修改useScrollPosition Hook

import { useState, useEffect, useCallback, RefObject } from 'react';

function useScrollPosition(elementRef?: RefObject<HTMLElement>) {
  const [scrollPosition, setScrollPosition] = useState(0);

  // 用useCallback缓存滚动处理函数,确保依赖变化时才更新
  const handleScroll = useCallback(() => {
    const target = elementRef?.current || window;
    let totalScrollableHeight: number;
    let currentScrollTop: number;

    if (target === window) {
      totalScrollableHeight = document.documentElement.scrollHeight - document.documentElement.clientHeight;
      currentScrollTop = document.body.scrollTop || document.documentElement.scrollTop;
    } else {
      totalScrollableHeight = target.scrollHeight - target.clientHeight;
      currentScrollTop = target.scrollTop;
    }

    // 处理无滚动空间的情况,避免NaN
    if (totalScrollableHeight <= 0) {
      setScrollPosition(0);
      return;
    }

    const scrolledPercentage = (currentScrollTop / totalScrollableHeight) * 100;
    setScrollPosition(scrolledPercentage);
  }, [elementRef]);

  useEffect(() => {
    const target = elementRef?.current || window;
    // 添加passive: true提升滚动性能(无需阻止默认行为)
    target.addEventListener('scroll', handleScroll, { passive: true });

    return () => {
      target.removeEventListener('scroll', handleScroll);
    };
  }, [elementRef, handleScroll]);

  return scrollPosition;
}

步骤2:在Feed组件中绑定滚动容器的Ref

// 导入useRef
import { useState, useEffect, useRef } from 'react';

export const Feed = () => {
  // ...其他代码保持不变

  // 创建滚动容器的Ref
  const feedScrollRef = useRef<HTMLDivElement>(null);
  // 将Ref传入自定义Hook
  const scrollPosition = useScrollPosition(feedScrollRef);

  // ...其他代码保持不变

  return (
    // 将Ref绑定到实际滚动的容器上
    <div className="h-full" ref={feedScrollRef}>
      {tweets.map((fullTweet) => (
        <TweetView
          tweetData={{ ...fullTweet }}
          key={fullTweet.tweet.id}
          input={{ limit: LIMIT }}
        />
      ))}
    </div>
  );
};

额外说明

  • 如果你的页面确实是整个窗口滚动(而非内部容器),可以不传入elementRef,Hook会自动监听window的滚动事件。
  • 添加passive: true是滚动事件监听的最佳实践,能避免浏览器的滚动卡顿问题。
  • 处理totalScrollableHeight <= 0的情况,防止出现NaN值导致状态异常。

内容的提问来源于stack exchange,提问作者TheInfamousGrim

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.25 14:12:53