React native

ReactNative之 FlatList 上拉加载更多

2019-03-17  本文已影响85人  楼上那只猫

FlatList 实现上拉加载更多,关键在于3个属性的设置

<FlatList
                    style={{flex: 1}}
                    data={records}
                    ListFooterComponent={this.renderFooter}
                    onEndReachedThreshold={0.1}
                    onEndReached={this.loadMore}
                    ListHeaderComponent={
                        <View style={{
                            height: 44,
                            justifyContent: 'center',
                            paddingLeft: 15,
                            backgroundColor: '#f3f4f6',
                        }}>
                            <Text style={{fontSize: 14, color: '#666666'}}>银行转账会扣除转账手续费,以实际到账金额为准</Text>
                        </View>
                    }
                    keyExtractor={(item, index) => index + ''}
                    renderItem={({item, index}) => {
                        return (
                            <JFTRecordItem
                                key={index + ''}
                                type={getRecordType(item.type)}
                                date={moment(item.submitTime).format('YYYY-MM-DD hh:mm:ss')}
                                cash={item.details.sum + getTradeCurrency(item.details.currency)}
                                state={getRecordStatus(item.status)}
                                lineProps={{left: 0}}
                                onPress={() => this.toRecordDetail(item)}
                            />

                        )
                    }}
                />

onEndReachedThreshold:决定当距离内容最底部还有多远时触发onEndReached回调。注意此参数是一个比值而非像素单位。比如,0.5 表示距离内容最底部的距离为当前列表可见长度的一半时触发.
onEndReached:当列表被滚动到距离内容最底部不足onEndReachedThreshold的距离时调用.
ListFooterComponent:尾部组件。可以是 React Component, 也可以是一个 render 函数,或者渲染好的 element。这里我们主要是用来渲染加载更多的组件。

这里我已一个具体的例子来说明。

  1. 首先,这是一个记录列表页面,刚进入页面时,会去请求第一页的数据,同时制定单页的 size
let page = 1;
constructor(props) {
        super(props);
        this.state = {
            showFooter: LOAD_MORE_STATE.CANCEL,
            noMoreData:false,
        };
    }

    componentDidMount() {
        this.props.getUserCashRecord({pageNum: page, pageSize: 15}).then((response) => {
            if (response.totalCount <= 15) {
                //总的数据条目少于初始请求的数据,隐藏 footer
                this.setState({showFooter: LOAD_MORE_STATE.CANCEL});
            }
        }, (err) => {

        });
    }

注意到请求完成的回调中,totalCount是服务器返回的记录列表的总数目,如果总数目就已经小于 size 了,那么说明只有一页数据,因此不需要有加载更多的功能。

  1. 如果size 小于 totalCount,说明数据大于1页,需要有加载更多,那么,当滑动到列表底部时,会触发我们在FlatList中设置的回调方法
loadMore = () => {
        if (this.state.showFooter !== LOAD_MORE_STATE.CANCEL || this.state.noMoreData) {
            return;
        }
        //正在加载中
        this.setState({showFooter: LOAD_MORE_STATE.REFRESHING});
        this.props.getUserCashRecord({pageNum: ++page, pageSize: 15}).then((response) => {
            if (0 === response.commissionList.length) {
                //全部数据加载完成,显示没有更多数据
                this.setState({showFooter: LOAD_MORE_STATE.NO_MORE_DATA, noMoreData:true});
            } else {
                this.setState({showFooter: LOAD_MORE_STATE.CANCEL});
            }
        }, (err) => {
            this.setState({showFooter: LOAD_MORE_STATE.CANCEL});
        });
    };

这个方法可能在一次回调中被多次调用,但是只有在有些情况下,我们才需要让列表进入加载更多的状态。

这里,如果当前state 的状态不为LOAD_MORE_STATE.CANCEL(也就是说处于REFRESHING或者NO_MORE_DATA状态),或者当前已没有更多数据的话,就直接返回,否则进入加载更多状态

if (this.state.showFooter !== LOAD_MORE_STATE.CANCEL || this.state.noMoreData) {
            return;
        }

注意,加载更多时 page 要递增,并且,在拿到最新获取的数据后,通过判断最新的数据是否为0来决定最新的刷新状态。

//正在加载中
        this.setState({showFooter: LOAD_MORE_STATE.REFRESHING});
        this.props.getUserCashRecord({pageNum: ++page, pageSize: 15}).then((response) => {
            if (0 === response.commissionList.length) {
                //全部数据加载完成,显示没有更多数据
                this.setState({showFooter: LOAD_MORE_STATE.NO_MORE_DATA, noMoreData:true});
            } else {
                this.setState({showFooter: LOAD_MORE_STATE.CANCEL});
            }
        }, (err) => {
            this.setState({showFooter: LOAD_MORE_STATE.CANCEL});
        });
  1. 最后,是渲染 footer 组件的方法
renderFooter = () => {
        return <JRNLoadMoreFooter state={this.state.showFooter}/>;
    };
export const LOAD_MORE_STATE = {
    CANCEL:0,   //无需加载更多
    REFRESHING:1, //正在加载更多数据
    NO_MORE_DATA:2, //没有更多数据
};

class JRNLoadMoreFooter extends PureComponent {
    render() {
        let {state, loadMoreTxt = '正在加载更多数据...', noMoreData = '没有更多数据了'} = this.props;
        return (
            <View>
                {
                    state === LOAD_MORE_STATE.CANCEL && <View style={{height: 0}}/>
                }
                {
                    state === LOAD_MORE_STATE.REFRESHING && <View style={{
                        flexDirection: 'row',
                        height: 34,
                        justifyContent: 'center',
                        backgroundColor:'#fff',
                        alignItems: 'center',
                    }}>
                        <ActivityIndicator/>
                        <Text style={{color: '#999999', fontSize: 13}}>{loadMoreTxt}</Text>
                    </View>
                }
                {
                    state === LOAD_MORE_STATE.NO_MORE_DATA &&
                    <View style={{height: 34, alignItems: 'center', justifyContent: 'center', backgroundColor:'#fff'}}>
                        <Text style={{color: '#999999', fontSize: 13}}>{noMoreData}</Text>
                    </View>
                }
            </View>

        )
    }
}

export default JRNLoadMoreFooter;

注意,在处理加载更多的时候,需要在 reducer 中对最新获得的数据处理,保证是拼接到数据后面

export const userCashRecordData = handleActions({
    [USER_CASH_RECORD]:(state, {payload}) => {
        if(state.commissionList.length < payload.totalCount) {
            return Object.assign({}, payload, {
                commissionList: state.commissionList.concat(payload.commissionList)
            });
        } else {
            return state;
        }
    },
}, {
    commissionList: [],
});

这里要注意,只有当前 state 中的总数据少于总数据时才拼接,大于的话,直接返回state 即可。

上一篇 下一篇

猜你喜欢

热点阅读