RN - ScrollView嵌套FlatList场景实现上拉加载分页

方法一简单介绍下未嵌套ScrollViewFlatList上拉加载应用场景,可自行忽略,直接跳至方法二嵌套scrollView场景。

一、FlatList未嵌套在ScrollView的应用场景

1、最简单的方法是应用react-native-refresh-list-view组件实现,其基于FlatList的二次封装。

通过控制RefreshState来实现下拉刷新或者上拉加载。

export const RefreshState = {
  Idle: 0,
  HeaderRefreshing: 1,
  FooterRefreshing: 2,
  NoMoreData: 3,
  Failure: 4,
  EmptyData: 5,
}

具体应用的部分代码如下:

import RefreshListView, { RefreshState } from "react-native-refresh-list-view";

renderRefreshList = () => {
    const { sourceData, refreshState } = this.state;
    return (
       this.renderSeparator()}
        keyExtractor={(item, idx) => idx.toString()}
        renderItem={({ item }) => this.renderCell(item)}
        ListHeaderComponent={this.renderHeader}
        refreshState={refreshState}
        onHeaderRefresh={this.onHeaderRefresh}
        onFooterRefresh={() => this.onCheckMore()}
        footerNoMoreDataText="已经到底了"
      />
    );
  };

2、如果不想使用方法1中的第三方组件,可以自定义上拉加载的组件

核心属性: onEndReachedThresholdonEndReached

onEndReachedThreshold设置大于1时,的确进入页面就触发,设置在0-1之间时按正常逻辑走。


上拉加载更多onReached被触发两次,造成重复请求资源,性能浪费

 {
    if (this.canLoadMore) {
        this.loadData(true); //
        this.canLoadMore = false;
    }
    }}
    onEndReachedThreshold={0.5}
    onMomentumScrollBegin={() => {
    this.canLoadMore = true; //初始化时调用onEndReached的loadMore
    }}
    ...
/>

通常情况下是先调用onMomentumScrollBegin,然后调用onEndReached,但是可能会存在意外情况

 {
    setTimeout(() => {
        if (this.canLoadMore) {
            this.loadData(true);
            this.canLoadMore = false;
        }
    }, 100)
    }}
    onEndReachedThreshold={0.5}
    onMomentumScrollBegin={() => {
    this.canLoadMore = true; //初始化时调用onEndReached的loadMore
    }}
    ...
/>

二、FlatList嵌套在ScrollView的应用场景

FlatList(或ListView)和其他子组件在外面加了一个ScrollView时,debugg发现在一直不停地触发onEndReached函数,也就是说父组件ScrollView能滚动,导致FlatList(或ListView)中的数据不能满屏,于是就不停地触发该函数,不停fetch请求。

还有,当FlatList(或ListView)的dataSource第一次渲染时,如果为空,也会触发onEndReached函数。

解决方案: 针对此问题,直接对最外层的scrollview实现上拉加载功能

  renderScrollView = () => {
    const { isRefreshing } = this.state;
    return (
       this.onScroll(event)}
        scrollEventThrottle={1}
        onMomentumScrollEnd={this.handleScrollEnd}
        refreshControl={
           this.onRefresh()}
          />
        }
      >
        {this.renderView()}
      
    );
  };


 // 判断上拉加载的时机
  handleScrollEnd = event => {
    const contentHeight = event.nativeEvent.contentSize.height;
    const scrollViewHeight = event.nativeEvent.layoutMeasurement.height;
    const scrollOffset = event.nativeEvent.contentOffset.y;

    // 是否滑动到底部
    const isEndReached = scrollOffset + scrollViewHeight >= contentHeight;
    // 内容高度是否大于列表高度
    const isContentFillPage = contentHeight >= scrollViewHeight;

    const { reqSsqData, reqJpqData, reqWbqData, reqInData } = this.state;

    if (isContentFillPage && isEndReached) {
      // 已滑动scrollview底部,触发加载分页请求
    }
  };
需要注意:

在判断上拉加载的时机时,主要是比较以下2个时机,根据自己的需求添加

// 滚动结束的回调
onMomentumScrollEnd={this.handleScrollEnd}

// 手指松开屏幕的回调
 onScrollEndDrag={this.handleScrollEnd}

参考:
https://www.jianshu.com/p/33ec6ceeb638
https://www.cnblogs.com/fe-linjin/p/10587720.html
https://blog.csdn.net/qq_21478985/article/details/80931386

你可能感兴趣的:(RN - ScrollView嵌套FlatList场景实现上拉加载分页)