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

使用react-infinite-scroller实现无限滚动:先报错后loadMore无响应

解决react-infinite-scroller的两个核心问题:属性未定义错误与loadMore不触发

我来帮你一步步搞定遇到的这两个问题,咱们先从第一个报错说起,再解决loadMore不触发的情况。

一、解决Uncaught (in promise) TypeError: Cannot read property 'companies' of undefined

这个错误本质上有两个常见原因,咱们逐一排查修复:

1. 函数上下文this丢失,无法访问组件state

你最初的代码里,fetchCompanies作为类方法直接传给loadMore时,没有绑定组件上下文,导致函数内部的this不是组件实例,自然读不到this.state.companies。

解决方法二选一:

  • 在构造函数里绑定方法:
constructor(props) {
  super(props);
  this.state = { companies: [], page: 0, resetResult: false };
  // 绑定上下文,确保函数内this指向组件实例
  this.fetchCompanies = this.fetchCompanies.bind(this);
}
  • 用箭头函数定义方法,自动绑定上下文:
// 箭头函数自动绑定组件this
fetchCompanies = (page) => {
  traineeship.getAll(page).then(response => {
    // ...你的业务逻辑
  });
}

2. API返回结构异常,_embedded.companies不存在

另一个可能是traineeship.getAll(page)返回的response.data里没有_embedded属性,直接访问_embedded.companies就会报错。咱们可以加一层安全判断,避免程序崩溃:

fetchCompanies = (page) => {
  traineeship.getAll(page).then(response => {
    // 用可选链操作符安全访问嵌套属性,避免undefined报错
    if (response.data?._embedded?.companies) {
      this.setState(prevState => ({
        // 用prevState获取最新状态,避免setState异步导致的旧值问题
        companies: [...prevState.companies, ...response.data._embedded.companies],
        page: prevState.page + 1 // 记得更新页码,否则每次都请求同一页
      }));
    } else {
      console.warn("API返回结构不符合预期", response);
    }
  }).catch(err => {
    console.error("请求公司列表失败", err); // 别忘了捕获异步请求错误
  });
}

二、解决loadMore完全不触发的问题

你修改后的代码里loadMore={() => this.fetchCompanies.bind(this)}是错误写法,还有几个关键配置没到位,咱们来修正:

1. 正确传递loadMore函数

loadMore需要接收一个可直接执行的函数,而且它会自动传递当前页码(基于pageStart),所以直接传绑定好上下文的方法即可:

<InfiniteScroll
  pageStart={0}
  loadMore={this.fetchCompanies} // 直接传绑定好的方法
  hasMore={this.state.hasMore} // 不要写死true,根据数据加载状态动态更新
  loader={<div className="loader" key={0}>Loading ...</div>}
  useWindow={false}
  style={{ height: '600px', overflowY: 'auto' }} // useWindow=false时必须设置容器高度和滚动属性
>
  {this.state.companies.map((company, key) => (
    // 列表项渲染,key尽量用数据唯一ID而非索引
    <div key={company.id || key}>{company.name}</div>
  ))}
</InfiniteScroll>

2. 动态控制hasMore状态

hasMore不能固定为true,否则会一直触发加载。你需要根据API返回的数据判断是否还有更多内容,比如返回的列表为空时,把hasMore设为false:

// 初始化state时添加hasMore字段
this.state = { companies: [], page: 0, resetResult: false, hasMore: true };

// 在fetchCompanies里更新hasMore
fetchCompanies = (page) => {
  // 已经没有更多数据时直接返回,避免重复请求
  if (!this.state.hasMore) return;

  traineeship.getAll(page)
    .then(response => {
      if (response.data?._embedded?.companies) {
        const newCompanies = response.data._embedded.companies;
        this.setState(prevState => ({
          companies: [...prevState.companies, ...newCompanies],
          page: prevState.page + 1,
          // 返回数据为空则标记无更多内容
          hasMore: newCompanies.length > 0
        }));
      } else {
        this.setState({ hasMore: false });
        console.warn("没有更多数据了");
      }
    })
    .catch(err => {
      console.error("请求失败", err);
      this.setState({ hasMore: false });
    });
}

3. useWindow={false}的必要配置

当设置useWindow={false}时,InfiniteScroll会监听自身容器的滚动事件,所以必须给容器设置固定高度和overflow-y: auto,否则容器不会出现滚动条,自然触发不了滚动加载。

最终完整代码示例

class Traineeship extends React.Component {
  constructor(props) {
    super(props);
    this.state = {
      companies: [],
      page: 0,
      resetResult: false,
      hasMore: true
    };
    this.fetchCompanies = this.fetchCompanies.bind(this);
  }

  componentDidMount() {
    this.fetchCompanies(this.state.page);
  }

  fetchCompanies(page) {
    if (!this.state.hasMore) return;

    traineeship.getAll(page)
      .then(response => {
        if (response.data?._embedded?.companies) {
          const newCompanies = response.data._embedded.companies;
          this.setState(prevState => ({
            companies: [...prevState.companies, ...newCompanies],
            page: prevState.page + 1,
            hasMore: newCompanies.length > 0
          }));
        } else {
          this.setState({ hasMore: false });
          console.warn("API返回无更多数据");
        }
      })
      .catch(err => {
        console.error("获取公司列表失败:", err);
        this.setState({ hasMore: false });
      });
  }

  render() {
    return (
      <div className="traineeship-container">
        <InfiniteScroll
          pageStart={0}
          loadMore={this.fetchCompanies}
          hasMore={this.state.hasMore}
          loader={<div className="loader" key={0}>Loading ...</div>}
          useWindow={false}
          style={{ height: '600px', overflowY: 'auto', padding: '10px' }}
        >
          {this.state.companies.map((company, key) => (
            <div key={company.id || key} className="company-item">
              <h3>{company.name}</h3>
              <p>{company.address}</p>
            </div>
          ))}
        </InfiniteScroll>
      </div>
    );
  }
}

额外注意事项

  • 确保traineeship.getAll(page)能正确接收page参数,并返回对应页码的数据;
  • 列表项的key优先使用数据的唯一ID(比如company.id),避免用数组索引导致渲染异常;
  • 如果需要重置列表(比如搜索后),可以重置companies、page和hasMore状态,再调用fetchCompanies(0)重新加载。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.28 10:12:21