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

React中Infinite Scrolling拉取数据失效导致运行卡顿问题

React无限滚动新闻列表卡死问题修复

核心卡死原因

你遇到的电脑卡死本质是请求死循环+内存爆炸,由几个写法错误共同导致:

  • 直接修改state:fetchMoreData里写this.state.page += this.state.page违反React类组件的状态更新规则,既不会触发正常的重渲染,还会让页码直接翻倍(1→2→4→8→16...指数级跳页)
  • 无限滚动组件判断hasMore条件始终成立,又找不到你配置的scrollableTarget="scrollableDiv"对应的DOM节点,会不停触发fetchMoreData回调,短时间内发出上百个接口请求,返回的大量数据塞满内存直接导致页面崩溃
  • 没有加载锁,上一个请求没返回的时候下一个请求已经发出去,进一步放大请求并发量
  • 列表项用数组下标做key,追加数据时React重复渲染DOM节点,越加载越卡
  • 错误开启inverse={true}配置,这个参数是给聊天框那种滚到顶部加载历史的场景用的,普通向下滚动的新闻列表开这个会导致滚动判断逻辑完全错乱

修复步骤

  1. 所有state修改必须走setState,页码更新逻辑改为每次+1,禁止直接赋值this.state.xxx
  2. 修正InfiniteScroll配置:关闭inverse,删掉不存在的scrollableTarget配置,默认绑定window滚动即可
  3. 给加载逻辑加锁,请求过程中禁止重复触发下一页拉取
  4. 列表项key改用新闻条目的唯一url字段,不要用数组下标
  5. 补全你代码里没写完的render闭合标签,避免编译异常

修复后的关键代码

修正fetchMoreData方法

async fetchMoreData() {
  // 加载中直接返回,防止重复触发
  if (this.state.loading) return;
  // 用setState的函数式更新拿最新页码,更新完再发请求
  this.setState(
    prev => ({ page: prev.page + 1, loading: true }),
    async () => {
      try {
        const url = `https://newsapi.org/v2/top-headlines?country=${this.props.country}&category=${this.props.category}&apiKey=01b1a8fe6ec74a02b41f4e0050d4d394&page=${this.state.page}&pageSize=${this.props.pageSize}`;
        const res = await fetch(url);
        const parsedData = await res.json();
        this.setState(prev => ({
          articles: prev.articles.concat(parsedData.articles || []),
          loading: false,
          totalResults: parsedData.totalResults
        }))
      } catch (err) {
        console.error("加载更多失败", err);
        this.setState({ loading: false })
      }
    }
  )
}

修正首次加载updateNews方法

async updateNews() {
  try {
    // 切换分类/首次加载时重置状态
    this.setState({
      loading: true,
      page: 1,
      articles: [],
      totalResults: 0
    })
    const url = `https://newsapi.org/v2/top-headlines?country=${this.props.country}&category=${this.props.category}&apiKey=01b1a8fe6ec74a02b41f4e0050d4d394&page=1&pageSize=${this.props.pageSize}`;
    const data = await fetch(url);
    const parsedData = await data.json();
    this.setState({
      articles: parsedData.articles || [],
      loading: false,
      totalResults: parsedData.totalResults
    })
  } catch (e) {
    console.log("新闻加载失败");
    this.setState({ loading: false })
  }
}

修正InfiniteScroll组件配置

<InfiniteScroll
  dataLength={this.state.articles.length}
  next={this.fetchMoreData}
  inverse={false}
  hasMore={this.state.articles.length < this.state.totalResults}
  loader={<Spinner />}
>
  <div className="container my-4">
    <div className="row">
      {this.state.articles.map((element) => {
        return (
          <div className="col-md-4 my-4" key={element.url}>
            <NewsItem
              title={element.title ? element.title.slice(0, 40) : ""}
              description={element.description ? element.description.slice(0, 40) : ""}
              urlToImage={element.urlToImage}
              author={element.author}
              date={element.publishedAt}
              url={element.url}
              source={element.source.name}
            />
          </div>
        )
      })}
    </div>
  </div>
</InfiniteScroll>

验证方式

改完后打开浏览器开发者工具的网络面板,正常逻辑是只有滚动到列表底部时才会发起一次下一页请求,不会出现连续批量发请求的情况,列表滚动流畅不会卡顿。如果还有频繁触发的问题,可以给fetchMoreData加300ms节流即可。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.29 09:21:35