React滚动动态分页:距离底部250px时一次性加载全部数据问题排查
异常成因
setState异步更新问题:scroll事件触发频率极高,当满足距离底部≤250px的条件时,首次触发逻辑后调用的setState不会立即更新isFetching和currentItem的值,后续连续触发的scroll事件读取到的还是更新前的isFetching=false状态,会重复执行加载逻辑,连续给currentItem累加10。- 阈值特性差异:阈值为0时,加载新数据后页面高度增加,滚动位置会自动脱离≤0的条件,不会重复触发;但阈值为250px时,新数据渲染后当前滚动位置大概率仍满足≤250px的条件,会持续触发加载逻辑。
- 判断条件遗漏:scrollHandler的触发判断没有加入
isFetching状态校验,即使已经处于加载流程中,只要满足距离和总量条件就会重复触发逻辑。 - 代码隐含bug:原有代码中合并数组的写法有误,
{...this.state.data, ...result.data}是将数组作为对象展开,会导致数据结构异常。
修复方案
- 调整scrollHandler的判断条件,加入
!this.state.isFetching的校验,只有当前未处于加载状态时才触发新的加载 - 改用函数式
setState更新依赖前序状态的变量,避免异步更新导致的取值错误 - 修正数组合并的写法,正确拼接新老数据
修复后完整代码如下:
import React, { Component } from 'react'; class Orders extends Component { constructor(props) { super(props); this.state = { data: [], isFetching: true, currentItem: 0, totalLoading: 0, totalCount: 33 }; } loadingData() { if (this.state.isFetching) { fetch('/api/orders', { method: 'POST', headers: { Accept: 'application/json', 'Content-Type': 'application/json', }, body: JSON.stringify({ 'limit': 10, 'item': this.state.currentItem }), }) .then(response => response.json()) .then(result => { this.setState(prevState => ({ data: [...prevState.data, ...result.data], totalLoading: prevState.totalLoading + result.data.length })); }) .finally(() => this.setState({ isFetching: false })); } } scrollHadler = () => { const distanceToBottom = document.documentElement.scrollHeight - (document.documentElement.scrollTop + window.innerHeight); // 加入isFetching判断,避免重复触发 if (distanceToBottom <= 250 && !this.state.isFetching && this.state.totalLoading < this.state.totalCount) { this.setState(prevState => ({ isFetching: true, currentItem: prevState.currentItem + 10 }), () => { // 等state更新完成后再调用加载方法,确保参数正确 this.loadingData(); }); } } componentDidMount() { this.loadingData(); document.addEventListener('scroll', this.scrollHadler); } componentWillUnmount() { document.removeEventListener('scroll', this.scrollHadler); } }
内容的提问来源于stack exchange,提问作者Vlad
相关产品推荐
相关产品推荐

