This article mainly introduces the example of React Native customizing the pull-down to refresh the pull-up loaded list. Now I share it with you and give it as a reference.
List pages are very common pages in mobile development. In React Native, we generally use FlatList or SectionList components to implement these list views. Usually the list page will have a large amount of data that needs to be loaded and displayed. At this time, paging loading is used. Therefore, for the list component, it is essential to implement pull-down refresh and pull-up loading in many cases.
This article encapsulates a RefreshListView based on FlatList that supports pull-down refresh and pull-up loading. After encapsulating the original FlatList, it is very convenient to call pull-up and pull-down refresh.
The implementation of pull-down refresh is very simple. Here we use the properties of FlatList itself to implement
onRefresh— After setting this option, a standard will be added to the head of the list RefreshControl control in order to implement the "pull-down refresh" function. At the same time you need to set the refreshing attribute correctly.
refreshing—— bool value, used to control the display and hiding of the refresh control. Set to false after the refresh is complete.
By setting these two properties, we can realize the refresh operation of the FlatList header. The control uses the default style, and Android and iOS use the components of their respective systems to display.
The key point is to pull up to load more. React Native’s list component does not have this function and we need to implement it ourselves. For pull-up loading, we usually have several states. Here I create a RefreshState.js file to store the pull-up loading state:
export default { Idle: 'Idle', // 初始状态,无刷新的情况 CanLoadMore: 'CanLoadMore', // 可以加载更多,表示列表还有数据可以继续加载 Refreshing: 'Refreshing', // 正在刷新中 NoMoreData: 'NoMoreData', // 没有更多数据了 Failure: 'Failure' // 刷新失败 }
Then encapsulate a RefreshFooter component based on these states so that it can be customized according to different states. The status displays different contents. Without further ado, let’s talk about the code:
import React, {Component} from 'react'; import {View, Text, ActivityIndicator, StyleSheet, TouchableOpacity} from 'react-native'; import RefreshState from './RefreshState'; import PropTypes from 'prop-types'; export default class RefreshFooter extends Component { static propTypes = { onLoadMore: PropTypes.func, // 加载更多数据的方法 onRetryLoading: PropTypes.func, // 重新加载的方法 }; static defaultProps = { footerRefreshingText: "努力加载中", footerLoadMoreText: "上拉加载更多", footerFailureText: "点击重新加载", footerNoMoreDataText: "已全部加载完毕" }; render() { let {state} = this.props; let footer = null; switch (state) { case RefreshState.Idle: // Idle情况下为null,不显示尾部组件 break; case RefreshState.Refreshing: // 显示一个loading视图 footer = <View style={styles.loadingView}> <ActivityIndicator size="small"/> <Text style={styles.refreshingText}>{this.props.footerRefreshingText}</Text> </View>; break; case RefreshState.CanLoadMore: // 显示上拉加载更多的文字 footer = <View style={styles.loadingView}> <Text style={styles.footerText}>{this.props.footerLoadMoreText}</Text> </View>; break; case RefreshState.NoMoreData: // 显示没有更多数据的文字,内容可以自己修改 footer = <View style={styles.loadingView}> <Text style={styles.footerText}>{this.props.footerNoMoreDataText}</Text> </View>; break; case RefreshState.Failure: // 加载失败的情况使用TouchableOpacity做一个可点击的组件,外部调用onRetryLoading重新加载数据 footer = <TouchableOpacity style={styles.loadingView} onPress={()=>{ this.props.onRetryLoading && this.props.onRetryLoading(); }}> <Text style={styles.footerText}>{this.props.footerFailureText}</Text> </TouchableOpacity>; break; } return footer; } } const styles = StyleSheet.create({ loadingView: { flexDirection: 'row', justifyContent: 'center', alignItems: 'center', padding: 15, }, refreshingText: { fontSize: 12, color: "#666666", paddingLeft: 10, }, footerText: { fontSize: 12, color: "#666666" } });
Note that propTypes is the method we define for the RefreshFooter component for external calls. The method type needs to be specified using PropTypes, and Facebook’s prop-types need to be installed. For dependent libraries, it is best to use yarn add prop-types to install them, which is less error-prone. This is used for runtime type checking. You can click here to learn more.
In defaultProps we define several default text contents in different states, which can be modified by passing values externally.
The next step is to implement this RefreshListView. First of all, it should be clear that this RefreshListView must have head refresh and tail refresh calling methods, and the specific method of calling data should be implemented externally. First define two methods like RefreshFooter:
static propTypes = { onHeaderRefresh: PropTypes.func, // 下拉刷新的方法,供外部调用 onFooterRefresh: PropTypes.func, // 上拉加载的方法,供外部调用 };
As mentioned above, the pull-down refresh of the head is implemented using FlatList’s own features. We need to define a bool value isHeaderRefreshing as the value of the refreshing attribute to control the display and display of the header. no. At the same time, define an isFooterRefreshing to determine the refresh status of the tail component. Define footerState to set the state of the current tail component as the value of RefreshFooter.
constructor(props) { super(props); this.state = { isHeaderRefreshing: false, // 头部是否正在刷新 isFooterRefreshing: false, // 尾部是否正在刷新 footerState: RefreshState.Idle, // 尾部当前的状态,默认为Idle,不显示控件 } }
render function is as follows:
render() { return ( <FlatList {...this.props} onRefresh={()=>{ this.beginHeaderRefresh() }} refreshing={this.state.isHeaderRefreshing} onEndReached={() => { this.beginFooterRefresh() }} onEndReachedThreshold={0.1} // 这里取值0.1(0~1之间不包括0和1),可以根据实际情况调整,取值尽量小 ListFooterComponent={this._renderFooter} /> ) } _renderFooter = () => { return ( <RefreshFooter state={this.state.footerState} onRetryLoading={()=>{ this.beginFooterRefresh() }} /> ) };
You can see that there are two methods, beginHeaderRefresh and beginFooterRefresh, in the above code. These two methods are used to call refresh, but before refreshing, there are Some logical situations require judgment. For example, the head and tail cannot be refreshed at the same time, otherwise the data processing results may be affected. Repeated refresh operations must be prevented during refreshing. These are all considerations. Here I have commented in detail in the code:
/// 开始下拉刷新 beginHeaderRefresh() { if (this.shouldStartHeaderRefreshing()) { this.startHeaderRefreshing(); } } /// 开始上拉加载更多 beginFooterRefresh() { if (this.shouldStartFooterRefreshing()) { this.startFooterRefreshing(); } } /*** * 当前是否可以进行下拉刷新 * @returns {boolean} * * 如果列表尾部正在执行上拉加载,就返回false * 如果列表头部已经在刷新中了,就返回false */ shouldStartHeaderRefreshing() { if (this.state.footerState === RefreshState.refreshing || this.state.isHeaderRefreshing || this.state.isFooterRefreshing) { return false; } return true; } /*** * 当前是否可以进行上拉加载更多 * @returns {boolean} * * 如果底部已经在刷新,返回false * 如果底部状态是没有更多数据了,返回false * 如果头部在刷新,则返回false * 如果列表数据为空,则返回false(初始状态下列表是空的,这时候肯定不需要上拉加载更多,而应该执行下拉刷新) */ shouldStartFooterRefreshing() { if (this.state.footerState === RefreshState.refreshing || this.state.footerState === RefreshState.NoMoreData || this.props.data.length === 0 || this.state.isHeaderRefreshing || this.state.isFooterRefreshing) { return false; } return true; }
The logic of startHeaderRefreshing and startFooterRefreshing is as follows:
/// 下拉刷新,设置完刷新状态后再调用刷新方法,使页面上可以显示出加载中的UI,注意这里setState写法 startHeaderRefreshing() { this.setState( { isHeaderRefreshing: true }, () => { this.props.onHeaderRefresh && this.props.onHeaderRefresh(); } ); } /// 上拉加载更多,将底部刷新状态改为正在刷新,然后调用刷新方法,页面上可以显示出加载中的UI,注意这里setState写法 startFooterRefreshing() { this.setState( { footerState: RefreshState.Refreshing, isFooterRefreshing: true }, () => { this.props.onFooterRefresh && this.props.onFooterRefresh(); } ); }
Before refreshing, we need to display the head or tail components and then call External data interface methods. The advantage of writing setState here is that the methods in the arrow function will be called only after the value in the state is updated. There is a strict order. If this.props.onFooterRefresh && this.props.onFooterRefresh() is written outside setState, On the UI, we may not see the loading in the head or the hard loading in the tail, but the interface method has already been called.
Finally, after the refresh is completed, we also need to call the stop refresh method so that the head or tail components are no longer displayed. Otherwise, it may be considered a bug if it is always loading. Let’s take a look at how to stop refreshing:
/** * 根据尾部组件状态来停止刷新 * @param footerState * * 如果刷新完成,当前列表数据源是空的,就不显示尾部组件了。 * 这里这样做是因为通常列表无数据时,我们会显示一个空白页,如果再显示尾部组件如"没有更多数据了"就显得很多余 */ endRefreshing(footerState: RefreshState) { let footerRefreshState = footerState; if (this.props.data.length === 0) { footerRefreshState = RefreshState.Idle; } this.setState({ footerState: footerRefreshState, isHeaderRefreshing: false, isFooterRefreshing: false }) }
Passing in a tail component status parameter here is to update the style of the tail component. At the same time, a judgment is made on the data source data. If it is empty, it means that there is currently no data and a blank page can be displayed. Then there is no need to display the tail component.
The following is the rendering of the Douban movie page page loading that I implemented using RefreshListView:
The above is what I compiled for everyone. I hope it will be helpful to everyone in the future.
Related articles:
Examples of set deduplication, intersection, union, and difference set functions implemented by JS
setTimeout time is set to 0Detailed analysis of
The method of index.js configuration file in the config directory of vue-cli scaffolding
The above is the detailed content of How to use Native in React to implement custom pull-down to refresh the list loaded by pull-up. For more information, please follow other related articles on the PHP Chinese website!