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。这里我们主要是用来渲染加载更多的组件。
这里我已一个具体的例子来说明。
- 首先,这是一个记录列表页面,刚进入页面时,会去请求第一页的数据,同时制定单页的 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 了,那么说明只有一页数据,因此不需要有加载更多的功能。
- 如果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});
});
- 最后,是渲染 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 即可。
网友评论