react-native 模仿原生 实现下拉刷新/上拉加载更多(RefreshListView)

1.下拉刷新/上拉加载更多 组件(RefreshListView)

src/components/RefreshListView/index.js

/**
 * 下拉刷新/上拉加载更多 组件(RefreshListView)
 */
import React, {PureComponent} from 'react';
import PropTypes from 'prop-types';
import {
  View,
  Text,
  StyleSheet,
  FlatList,
  ActivityIndicator,
  TouchableOpacity,
  ViewPropTypes,
  RefreshControl
} from 'react-native'

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

class RefreshListView extends PureComponent {
  static propTypes = {
    data: PropTypes.array.isRequired,
    renderItem: PropTypes.func.isRequired,
    refreshState: PropTypes.number.isRequired,

    listRef: PropTypes.node,
    onHeaderRefresh: PropTypes.func,
    footerContainerStyle: ViewPropTypes.style,
    footerTextStyle: ViewPropTypes.style,

    disabledSeparator: PropTypes.bool,
    disabledHeaderRefresh: PropTypes.bool,
    footerRefreshingText: PropTypes.string,
    footerFailureText: PropTypes.string,
    footerNoMoreDataText: PropTypes.string,
    footerEmptyDataText: PropTypes.string,

    ListEmptyComponent: PropTypes.node,
    footerRefreshingComponent: PropTypes.node,
    footerFailureComponent: PropTypes.node,
    footerNoMoreDataComponent: PropTypes.node,
    footerEmptyDataComponent: PropTypes.node,
  }

  static defaultProps = {
    disabledHeaderRefresh: false,
    footerRefreshingText: '数据加载中…',
    footerFailureText: '点击重新加载',
    footerNoMoreDataText: '已加载全部数据',
    footerEmptyDataText: '暂时没有相关数据',
  }

  componentWillReceiveProps(nextProps) {}

  componentDidUpdate(prevProps, prevState) {}

  onHeaderRefresh = () => {
    if (this.shouldStartHeaderRefreshing()) {
      this.props.onHeaderRefresh(RefreshState.HeaderRefreshing)
    }
  }

  onEndReached = () => {
    if (this.shouldStartFooterRefreshing()) {
      this.props.onFooterRefresh && this.props.onFooterRefresh(RefreshState.FooterRefreshing)
    }
  }

  shouldStartHeaderRefreshing = () => {
    if (this.props.refreshState == RefreshState.HeaderRefreshing || this.props.refreshState == RefreshState.FooterRefreshing) {
      return false
    }
    return true
  }

  shouldStartFooterRefreshing = () => {
    const {refreshState, data} = this.props
    if (data.length == 0) {
      return false
    }
    return (refreshState == RefreshState.Idle)
  }

  renderSeparator = () => (
    
  )

  renderFooter = () => {
    let footer = null

    let {
      footerRefreshingText,
      footerFailureText,
      footerNoMoreDataText,
      footerEmptyDataText,

      footerRefreshingComponent,
      footerFailureComponent,
      footerNoMoreDataComponent,
      footerEmptyDataComponent,
    } = this.props

    switch (this.props.refreshState) {
      case RefreshState.Idle: {
        footer = ()
        break
      }
      case RefreshState.Failure: {
        footer = (
           {
            if (this.props.data.length == 0) {
              this.props.onHeaderRefresh && this.props.onHeaderRefresh(RefreshState.HeaderRefreshing)
            } else {
              this.props.onFooterRefresh && this.props.onFooterRefresh(RefreshState.FooterRefreshing)
            }
          }}
          >
            {footerFailureComponent ? footerFailureComponent : (
              
                {footerFailureText}
              
            )}
          
        )
        break
      }
      case RefreshState.EmptyData: {
        footer = (
           {
            this.props.onHeaderRefresh && this.props.onHeaderRefresh(RefreshState.HeaderRefreshing)
          }}
          >
            {footerEmptyDataComponent ? footerEmptyDataComponent : (
              
                {footerEmptyDataText}
              
            )}
          
        )
        break
      }
      case RefreshState.FooterRefreshing: {
        footer = footerRefreshingComponent ? footerRefreshingComponent : (
          
            
            {footerRefreshingText}
          
        )
        break
      }
      case RefreshState.NoMoreData: {
        footer = footerNoMoreDataComponent ? footerNoMoreDataComponent : (
          
            {footerNoMoreDataText}
          
        )
        break
      }
    }
    return footer
  }

  render() {
    const {renderItem, ...rest} = this.props
    return (
      }
        // 决定当距离内容最底部还有多远时触发onEndReached回调
        onEndReachedThreshold={0.1}
        // 根据行数据data,渲染每一行的组件
        renderItem={renderItem}
      />
    )
  }
}

const styles = StyleSheet.create({
  footerContainer: {
    flex: 1,
    flexDirection: 'row',
    justifyContent: 'center',
    alignItems: 'center',
    padding: 10,
    height: 44,
  },
  footerText: {
    fontSize: 14,
    color: '#555555',
  },
})

export {
  RefreshState,
}

export default RefreshListView;

2.页面调用

(1)定义全局变量

// 刷新状态
global.RefreshState = {
  Idle: 0, // 加载成功
  HeaderRefreshing: 1, // 开始下拉刷新
  FooterRefreshing: 2, // 开始上拉翻页
  NoMoreData: 3, // 加载全部数据
  Failure: 4, // 加载失败
  EmptyData: 5, // 服务器没有数据
}

(2)通用store

@observable
refreshState: any;

/**
 * 改变refreshState的值
 * @param refreshState
 */
@action setRefreshState(refreshState) {
  this.refreshState = refreshState
}

(3)当前 store

// 加载成功
this.setRefreshState(RefreshState.Idle);

if(!res.data.topics.length){
  // 服务器没有数据
  this.setRefreshState(RefreshState.EmptyData);
}

(4)页面

const { data, refreshState, loadData, loadMoreData } = this.store;

// 新闻列表
store = new NewsStore();
 
// 子组件渲染
_renderRow(obj) {
  let item = obj.item;
  return (
     {
        // 跳转详情页
        Actions.homeDetailPage({detail: item})
      }}
    />
  )
}

 index.toString()}
  renderItem={this._renderRow.bind(this)}

  refreshState={refreshState}
  onHeaderRefresh={loadData.bind(this.store)}
  onFooterRefresh={loadMoreData.bind(this.store)}
/>

3.效果图

react-native 模仿原生 实现下拉刷新/上拉加载更多(RefreshListView)_第1张图片

你可能感兴趣的:(react-native 模仿原生 实现下拉刷新/上拉加载更多(RefreshListView))