基于FlatList实现的上拉加载,下拉刷新

2,783 阅读2分钟

最近一直在做react-native相关的项目,根据需求做了一个上拉加载,下拉刷新的组件

组件内容

// 引入公用组件  Results 是一个显示各种状态的组件
import { Results } from './components/index.js'

class ReFlatList extends Component {
	static propTypes = {

	}

	constructor(props) {
		super(props)
		this.state = {}
	}

	ListEmptyComponent = () => {
		const { data } = this.props
		if (data.error) {
			return <Results type='error' width={size(500)} height={size(200)} />
		}
		if (data.pageNum == 0) {
			return <Results type='reload' width={size(500)} height={size(200)} />
		}
		return <Results type='data' width={size(500)} height={size(200)} />
	}

	ListFooterComponent = () => {
		const { data } = this.props
		if (data.records.length > 0) {
			if (data.records.length < data.total) {
				return (
					<View style={{ padding: 20, }}>
						<ActivityIndicator text="正在加载" />
					</View>
				)
			} else {
				return (
					<View style={{ padding: 20, }}>
						<Text style={{ fontSize: 14, color: '#61676F', lineHeight: 16, textAlign: 'center' }}>到底了</Text>
					</View>
				)
			}
		}
		return null
	}

	render() {
		const { style, flatListStyle, progressBackgroundColor, data, ...props } = this.props
		return (
			<View style={{
				flex: 1,
				...style
			}}>
				<FlatList
					style={{
						flex: 1,
						...flatListStyle
					}}
					keyExtractor={(item, index) => index.toString()}
					ListEmptyComponent={this.ListEmptyComponent}
					ListFooterComponent={this.ListFooterComponent}
					onEndReachedThreshold={.0000001}
					data={data.records}
					{...props}
				/>
			</View>
		)
	}
}

使用方式

// antd 按需加载
import { Tabs, Toast, Portal } from '@ant-design/react-native';

// 引入 处理数据 所需文件
import { agentGoodsList } from './module/module.js'

// 引入公用组件
import { RnFlatList } from './components/index.js'

class AgentGoods extends Component {

  constructor(props) {
    super(props)
    this.state = {
      refreshing: false, // 刷新的的状态
      loading: false, // 加载的状态
      dataList: { // 存储接口返回的分页信息
        total: 0,
        size: 10,
        current: 1,
        pages: 1,
        records: [] // 实际的数据
      }
    }
  }

  componentDidMount() {
    // 进入页面后打开 loading 状态
    this.loading = Toast.loading('加载中')
    this.handleData({
      current: 1,
    })
  }

  // 处理数据请求
  handleData(options) {
    const { data, productId } = this.props
    agentGoodsList({
      productId,
      size: 10,
      ...options
    }).then(res => {
      Portal.remove(this.loading)
      this.setState({
        dataList: {
          ...res.data,
          records: this.state.dataList.records.concat(res.data.records)
        }
      })
    }).catch(error => {
      console.log(error, 11111)
    })
  }

  onRefresh = () => {
    this.setState({ refreshing: true });
    const { data, productId } = this.props
    const { dataList: { size } } = this.state
    agentGoodsList({
      current: 1,
      productId,
      size: 10,
    }).then(res => {
      this.setState({
        dataList: res.data,
        refreshing: false
      })
    }).catch(error => {
      console.log(error, 11111)
    })
  }

  onEndReached = () => {
    const { dataList: { current, size, records, total } } = this.state
    if (records.length < total) {
      this.handleData({
        current: current + 1,
      })
    }
  }

  onScroll = (e) => {
    const { searchBackgroundColor } = this.state
    if (e.nativeEvent.contentOffset.y >= size(366) - 44) {
      this.setState({
        searchBackgroundColor: '#e43130'
      })
    } else {
      this.setState({
        searchBackgroundColor: 'transparent'
      })
    }
  }

  render() {
    const { refreshing, dataList } = this.state
    const { integral } = this.props
    return (
      <View style={Style.container}>
        <Status />
        <RnFlatList
          style={{
            flex: 1,
            backgroundColor: '#f0f2f5',
          }}
          columnWrapperStyle={{
            paddingTop: 10,
          }}
          onScroll={this.onScroll}
          refreshing={refreshing}
          onRefresh={this.onRefresh}
          onEndReached={this.onEndReached}
          numColumns={2}
          removeClippedSubviews={true}
          data={dataList}
          renderItem={({ item, index }) => {
            const width = (ScreenWidth - 30) / 2
            return (
              <View style={{
                width: width,
                backgroundColor: '#fff',
                // margin: 3
                marginLeft: 10,
                borderRadius: 10,
                overflow: 'hidden'
                // marginBottom: 3
              }}>
                <TouchableOpacity
                  onPress={() => {
                    Actions.goodDetails({ goodsId: item.id, productId: item.productId, })
                  }}
                >
                  <CacheImage
                    resizeMod={"contain"}
                    style={{
                      width: width,
                      height: width,
                    }}
                    source={{ uri: `${pathHead}${item.goodsMainPic}` }}
                    defaultSource={background}
                  />
                </TouchableOpacity>
              </View>
            )
          }}
        />
      </View >
    );
  }
}