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

Next.js无限滚动首次触发加载时重复渲染最后一条元素问题

问题原因

三个核心问题导致首次加载重复:

  1. 分页计数器初始值错误:服务端getServerSideProps已经请求了start=0, limit=10的第一页10条数据,但客户端pageCounter初始值默认为0,第一次触发无限滚动的加载方法时,传入的分页起点还是0,会重复请求第一页数据,和已有列表拼接后就会出现重复内容。第一次请求结束后pageCounter被更新为10,后续分页就会正常,所以异常仅在首次触发时出现。
  2. 列表key设置错误:渲染文章卡片时使用newKey()生成随机值作为key,React每次重渲染都会生成全新的随机key,无法正确识别DOM节点对应关系,会出现节点复用错乱、内容重复渲染的问题。
  3. 缺少初始加载控制:react-infinite-scroller默认会在组件挂载时自动触发一次loadMore,和首屏服务端加载逻辑冲突,容易触发重复请求。
修复方案

按以下步骤调整代码即可解决问题:

  • 修正分页计数器初始值:首屏已经加载10条数据,客户端初始化pageCounter时直接设为10,同时初始化hasMore状态判断首屏是否已经加载完全部数据。
  • 给InfiniteScroll组件添加initialLoad={false}属性,禁止组件初始化时自动触发加载,首屏数据完全由服务端渲染提供。
  • 添加请求锁,防止滚动事件高频触发导致重复请求。
  • 替换列表渲染的key值,使用Strapi返回的文章唯一id作为key,保证同一条数据的key固定,避免React渲染错位。
修复后核心代码

状态初始化

// posts初始值直接用服务端返回的articles
const [posts, setPosts] = useState(articles)
const [pageCounter, setPageCounter] = useState(10)
const [hasMore, setHasMore] = useState(total > 10)
const [loading, setLoading] = useState(false)

加载更多方法

const getMorePost = async () => {
  if (loading || pageCounter >= total) {
    setHasMore(pageCounter < total)
    return
  }
  setLoading(true)
  try {
    const res = await getArticles({locale}, cookieJwt, pageCounter, 10)
    const newPosts = res.articlesList
    setPosts(prev => [...prev, ...newPosts])
    setPageCounter(prev => prev + 10)
    setHasMore(pageCounter + 10 < total)
  } catch (e) {
    console.error('加载文章失败', e)
  } finally {
    setLoading(false)
  }
}

无限滚动组件调整

<InfiniteScroll
  pageStart={0}
  loadMore={getMorePost}
  hasMore={hasMore}
  initialLoad={false}
  loader={<div className={cardStyle.loaderWrapper}><div className={cardStyle.loader}><Loader color={'orange'} variant={'bars'} /></div></div>}
>
  <SimpleGrid 
    cols={3}
    spacing="xl"
    breakpoints={[
      { maxWidth: 1200, cols: 2, spacing: 'md' },
      { maxWidth: 755, cols: 1, spacing: 'sm' },
    ]}
  >
    {posts.map((article) => (
      <ArticleCard 
        key={article.id}
        data={article} 
        locale={locale} 
        onClick={() => handleClick(article)} 
      />
    ))}
  </SimpleGrid>
</InfiniteScroll>

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.29 01:57:12