react-virtualized中InfiniteLoader与Masonry集成失效问题咨询
嘿,我之前在react-virtualized里结合Masonry和InfiniteLoader时也踩过一模一样的坑!这俩组件凑一起确实容易因为细节没到位导致加载回调不触发,给你梳理几个关键的排查点和修复办法:
关键排查与修复步骤
1. 务必给InfiniteLoader设置正确的rowCount
InfiniteLoader需要知道包含未加载内容的总行数才能判断何时触发加载。如果只传已加载的items长度,它会误以为所有内容都加载完了,自然不会调用loadMoreRows。
// ❌ 错误示例:仅传入已加载的数量 <InfiniteLoader rowCount={this.state.items.length} isRowLoaded={this._isRowLoaded} loadMoreRows={this._loadMoreRows} > {/* ... */} </InfiniteLoader> // ✅ 正确示例:设置为已加载+预估未加载的总数(加载后更新) <InfiniteLoader rowCount={this.state.totalItems} // 比如初始设为20,每次加载后加10 isRowLoaded={this._isRowLoaded} loadMoreRows={this._loadMoreRows} > {/* ... */} </InfiniteLoader>
2. 确保Masonry正确传递onRowsRendered和registerChild
InfiniteLoader的子函数会返回这两个关键参数,必须准确传给Masonry:
registerChild用来让InfiniteLoader监听Masonry的滚动与渲染状态onRowsRendered用来告知InfiniteLoader当前渲染的行范围,触发加载判断
// ✅ 正确的嵌套写法 <InfiniteLoader rowCount={this.state.totalItems} isRowLoaded={index => index < this.state.items.length} loadMoreRows={({ startIndex, stopIndex }) => { // 这里处理异步加载逻辑,记得返回Promise return fetchNewItems().then(newItems => { this.setState(prev => ({ items: [...prev.items, ...newItems], totalItems: prev.totalItems + newItems.length })); }); }} > {({ onRowsRendered, registerChild }) => ( <Masonry ref={registerChild} onRowsRendered={onRowsRendered} width={this.props.width} height={800} // 必须设置固定高度,你移除WindowScroller的操作是对的 columnCount={2} rowHeight={300} rowRenderer={({ index, key, style }) => ( <div key={key} style={style}> {this.state.items[index]} </div> )} /> )} </InfiniteLoader>
3. 检查isRowLoaded的逻辑是否正确
这个函数要返回true表示该行已加载,false表示未加载。如果逻辑写反,InfiniteLoader会认为所有行都已加载:
// ✅ 正确的判断逻辑 _isRowLoaded = index => { // 索引小于已加载数组长度,说明该行已加载 return index < this.state.items.length; };
4. 保证loadMoreRows返回Promise
InfiniteLoader依赖Promise来判断加载是否完成,如果不返回Promise,可能会出现重复触发或不触发后续加载的情况:
// ✅ 返回Promise的示例 _loadMoreRows = ({ startIndex, stopIndex }) => { return new Promise((resolve) => { // 模拟异步请求 setTimeout(() => { const newItems = Array.from({ length: 10 }, (_, i) => `Item ${this.state.items.length + i}`); this.setState(prev => ({ items: [...prev.items, ...newItems], totalItems: prev.totalItems + 10 }), resolve); // 状态更新完成后再resolve }, 1000); }); };
如果以上几点都排查过还是不行,可以试试打印onRowsRendered的参数,看看InfiniteLoader是否接收到了正确的渲染行范围,或者检查Masonry的rowRenderer是否正确渲染了每一行。
内容的提问来源于stack exchange,提问作者João Cunha
相关产品推荐
相关产品推荐

